summaryrefslogtreecommitdiff
path: root/game/shared/dod
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/dod
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/shared/dod')
-rw-r--r--game/shared/dod/achievements_dod.cpp905
-rw-r--r--game/shared/dod/dod_gamemovement.cpp1405
-rw-r--r--game/shared/dod/dod_gamerules.cpp5595
-rw-r--r--game/shared/dod/dod_gamerules.h526
-rw-r--r--game/shared/dod/dod_player_shared.cpp1396
-rw-r--r--game/shared/dod/dod_player_shared.h285
-rw-r--r--game/shared/dod/dod_playeranimstate.cpp1454
-rw-r--r--game/shared/dod/dod_playeranimstate.h62
-rw-r--r--game/shared/dod/dod_playerclass_info_parse.cpp163
-rw-r--r--game/shared/dod/dod_playerclass_info_parse.h55
-rw-r--r--game/shared/dod/dod_round_timer.cpp183
-rw-r--r--game/shared/dod/dod_round_timer.h67
-rw-r--r--game/shared/dod/dod_shareddefs.cpp276
-rw-r--r--game/shared/dod/dod_shareddefs.h691
-rw-r--r--game/shared/dod/dod_usermessages.cpp65
-rw-r--r--game/shared/dod/dod_viewmodel.cpp151
-rw-r--r--game/shared/dod/dod_viewmodel.h60
-rw-r--r--game/shared/dod/dod_weapon_parse.cpp195
-rw-r--r--game/shared/dod/dod_weapon_parse.h103
-rw-r--r--game/shared/dod/fx_dod_shared.cpp370
-rw-r--r--game/shared/dod/fx_dod_shared.h44
-rw-r--r--game/shared/dod/weapon_30cal.cpp423
-rw-r--r--game/shared/dod/weapon_amerknife.cpp77
-rw-r--r--game/shared/dod/weapon_bar.cpp84
-rw-r--r--game/shared/dod/weapon_bazooka.cpp104
-rw-r--r--game/shared/dod/weapon_c96.cpp131
-rw-r--r--game/shared/dod/weapon_colt.cpp128
-rw-r--r--game/shared/dod/weapon_dodbase.cpp1416
-rw-r--r--game/shared/dod/weapon_dodbase.h403
-rw-r--r--game/shared/dod/weapon_dodbasebomb.cpp375
-rw-r--r--game/shared/dod/weapon_dodbasebomb.h87
-rw-r--r--game/shared/dod/weapon_dodbasegrenade.cpp474
-rw-r--r--game/shared/dod/weapon_dodbasegrenade.h90
-rw-r--r--game/shared/dod/weapon_dodbasegun.cpp252
-rw-r--r--game/shared/dod/weapon_dodbasegun.h83
-rw-r--r--game/shared/dod/weapon_dodbasemelee.cpp237
-rw-r--r--game/shared/dod/weapon_dodbasemelee.h57
-rw-r--r--game/shared/dod/weapon_dodbaserpg.cpp345
-rw-r--r--game/shared/dod/weapon_dodbaserpg.h88
-rw-r--r--game/shared/dod/weapon_dodbipodgun.cpp782
-rw-r--r--game/shared/dod/weapon_dodbipodgun.h92
-rw-r--r--game/shared/dod/weapon_dodfireselect.cpp211
-rw-r--r--game/shared/dod/weapon_dodfireselect.h73
-rw-r--r--game/shared/dod/weapon_dodfullauto.cpp32
-rw-r--r--game/shared/dod/weapon_dodfullauto.h36
-rw-r--r--game/shared/dod/weapon_dodfullauto_punch.cpp84
-rw-r--r--game/shared/dod/weapon_dodfullauto_punch.h34
-rw-r--r--game/shared/dod/weapon_dodsemiauto.cpp37
-rw-r--r--game/shared/dod/weapon_dodsemiauto.h40
-rw-r--r--game/shared/dod/weapon_dodsniper.cpp414
-rw-r--r--game/shared/dod/weapon_dodsniper.h111
-rw-r--r--game/shared/dod/weapon_explodinghandgrenade.cpp52
-rw-r--r--game/shared/dod/weapon_explodingstickgrenade.cpp54
-rw-r--r--game/shared/dod/weapon_garand.cpp203
-rw-r--r--game/shared/dod/weapon_gerknife.cpp56
-rw-r--r--game/shared/dod/weapon_greasegun.cpp64
-rw-r--r--game/shared/dod/weapon_handgrenade.cpp49
-rw-r--r--game/shared/dod/weapon_k98.cpp140
-rw-r--r--game/shared/dod/weapon_k98_scoped.cpp156
-rw-r--r--game/shared/dod/weapon_m1carbine.cpp76
-rw-r--r--game/shared/dod/weapon_mg34.cpp207
-rw-r--r--game/shared/dod/weapon_mg42.cpp843
-rw-r--r--game/shared/dod/weapon_mg42.h108
-rw-r--r--game/shared/dod/weapon_mp40.cpp94
-rw-r--r--game/shared/dod/weapon_mp44.cpp87
-rw-r--r--game/shared/dod/weapon_p38.cpp115
-rw-r--r--game/shared/dod/weapon_pschreck.cpp102
-rw-r--r--game/shared/dod/weapon_riflegrenade.cpp233
-rw-r--r--game/shared/dod/weapon_riflegrenade.h48
-rw-r--r--game/shared/dod/weapon_riflegrenade_ger.cpp91
-rw-r--r--game/shared/dod/weapon_riflegrenade_ger_live.cpp56
-rw-r--r--game/shared/dod/weapon_riflegrenade_us.cpp91
-rw-r--r--game/shared/dod/weapon_riflegrenade_us_live.cpp56
-rw-r--r--game/shared/dod/weapon_smokegrenade_ger.cpp55
-rw-r--r--game/shared/dod/weapon_smokegrenade_us.cpp51
-rw-r--r--game/shared/dod/weapon_spade.cpp71
-rw-r--r--game/shared/dod/weapon_spring.cpp156
-rw-r--r--game/shared/dod/weapon_stickgrenade.cpp82
-rw-r--r--game/shared/dod/weapon_thompson.cpp81
79 files changed, 24328 insertions, 0 deletions
diff --git a/game/shared/dod/achievements_dod.cpp b/game/shared/dod/achievements_dod.cpp
new file mode 100644
index 0000000..b55b2b4
--- /dev/null
+++ b/game/shared/dod/achievements_dod.cpp
@@ -0,0 +1,905 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "cbase.h"
+
+#ifdef CLIENT_DLL
+
+#include "achievementmgr.h"
+#include "baseachievement.h"
+#include "c_dod_player.h"
+#include "dod_shareddefs.h"
+#include "c_dod_objective_resource.h"
+#include "dod_gamerules.h"
+
+CAchievementMgr g_AchievementMgrDOD; // global achievement mgr for DOD
+
+//-----------------------------------------------------------------------------
+// Purpose: Query if the gamerules allows achievement progress at this time
+//-----------------------------------------------------------------------------
+bool GameRulesAllowsAchievements( void )
+{
+ return ( DODGameRules()->State_Get() == STATE_RND_RUNNING );
+}
+
+class CAchievementDODThrowBackGren : public CBaseAchievement
+{
+ void Init()
+ {
+ // listen for player kill enemy events, base class will increment count each time that happens
+ SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( !GameRulesAllowsAchievements() )
+ return;
+
+ C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
+
+ if ( pAttacker == pLocalPlayer && pVictim->GetTeamNumber() != pAttacker->GetTeamNumber() )
+ {
+ // if we are allies and killed with a german grenade
+ // or if we are axis and killed with a us grenade
+
+ const char *killedwith = event->GetString( "weapon" );
+ int iLocalTeam = pLocalPlayer->GetTeamNumber();
+
+ if ( ( iLocalTeam == TEAM_ALLIES && ( FStrEq( killedwith, "frag_ger" ) || FStrEq( killedwith, "riflegren_ger" ) ) ) ||
+ ( iLocalTeam == TEAM_AXIS && ( FStrEq( killedwith, "frag_us" ) || FStrEq( killedwith, "riflegren_us" ) ) ) )
+ {
+ // This kill was made with an enemy grenade.
+ IncrementCount();
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODThrowBackGren, ACHIEVEMENT_DOD_THROW_BACK_GREN, "DOD_THROW_BACK_GREN", 1 );
+
+
+class CAchievementDODConsecutiveHeadshots : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+
+ // Handled on server
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODConsecutiveHeadshots, ACHIEVEMENT_DOD_CONSECUTIVE_HEADSHOTS, "DOD_CONSECUTIVE_HEADSHOTS", 1 );
+
+
+class CAchievementDODMGPositionStreak : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+
+ // Handled on server
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODMGPositionStreak, ACHIEVEMENT_DOD_MG_POSITION_STREAK, "DOD_MG_POSITION_STREAK", 1 );
+
+
+class CAchievementDODWinKnifeFight : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( !GameRulesAllowsAchievements() )
+ return;
+
+ C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
+
+ if ( pAttacker == pLocalPlayer && pVictim->GetTeamNumber() != pAttacker->GetTeamNumber() )
+ {
+ const char *killedwith = event->GetString( "weapon" );
+
+ if ( FStrEq( killedwith, "amerknife" ) || FStrEq( killedwith, "spade" ) )
+ {
+ C_DODPlayer *pDodVictim = ToDODPlayer( pVictim );
+
+ if ( pDodVictim )
+ {
+ CWeaponDODBase *pWpn = pDodVictim->GetActiveDODWeapon();
+
+ if ( pWpn && pWpn->GetDODWpnData().m_WeaponType == WPN_TYPE_MELEE )
+ {
+ // Kill was made with a melee weapon, killer had melee weapon out
+ IncrementCount();
+ }
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODWinKnifeFight, ACHIEVEMENT_DOD_WIN_KNIFE_FIGHT, "DOD_WIN_KNIFE_FIGHT", 1 );
+
+const char *pszOfficialMaps[] =
+{
+ "dod_anzio",
+ "dod_avalanche",
+ "dod_argentan",
+ "dod_colmar",
+ "dod_donner",
+ "dod_flash",
+ "dod_jagd",
+ "dod_kalt",
+ "dod_palermo"
+};
+
+
+class CAchievementDODCustomMaps : public CBaseAchievement
+{
+ // Requires a player to kill at least one player on 5 different non-official maps
+
+ void Init()
+ {
+ SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
+ SetGoal( 5 );
+ SetStoreProgressInSteam( true );
+
+ m_bCheckedCurrentMap = false;
+ }
+
+ virtual void ListenForEvents()
+ {
+ // hax, this is called from LevelInitPreEntity, init per-level here
+ m_bCheckedCurrentMap = false;
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( m_bCheckedCurrentMap )
+ return;
+
+ // don't store the map name if we're not going to give achievement progress
+ if ( m_pAchievementMgr->WereCheatsEverOn() )
+ return;
+
+ C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
+
+ if ( pAttacker == pLocalPlayer && pVictim->GetTeamNumber() != pAttacker->GetTeamNumber() )
+ {
+ char szMap[MAX_PATH];
+ Q_FileBase( engine->GetLevelName(), szMap, ARRAYSIZE( szMap ) );
+
+ if ( !IsOfficialMap( szMap ) && !HasPlayedThisCustomMap() )
+ {
+ IncrementCount();
+
+ UTIL_IncrementMapKey( "killed_a_player" );
+ }
+
+ // stop listening
+ m_bCheckedCurrentMap = true;
+ }
+ }
+
+ bool HasPlayedThisCustomMap( void )
+ {
+ return ( UTIL_GetMapKeyCount( "killed_a_player" ) > 0 );
+ }
+
+ bool IsOfficialMap( const char *pszMapName )
+ {
+ bool bFound = false;
+
+ for ( int i=0;i<ARRAYSIZE(pszOfficialMaps);i++ )
+ {
+ if ( FStrEq( pszMapName, pszOfficialMaps[i] ) )
+ {
+ bFound = true;
+ break;
+ }
+ }
+
+ return bFound;
+ }
+
+ bool m_bCheckedCurrentMap;
+
+};
+DECLARE_ACHIEVEMENT( CAchievementDODCustomMaps, ACHIEVEMENT_DOD_PLAY_CUSTOM_MAPS, "DOD_PLAY_CUSTOM_MAPS", 1 );
+
+
+class CAchievementDODKillsWithGrenade : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+ }
+
+ virtual void ListenForEvents()
+ {
+ // hax, this is called from LevelInitPreEntity, init per-level here
+ m_flLastKillTime = 0;
+ m_iKillCount = 0;
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( !GameRulesAllowsAchievements() )
+ return;
+
+ C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
+
+ if ( pAttacker == pLocalPlayer )
+ {
+ // reject non-grenade/non-rocket inflictors
+ const char *killedwith = event->GetString( "weapon" );
+
+ if ( Q_strncmp( killedwith, "frag_", 5 ) &&
+ Q_strncmp( killedwith, "riflegren_", 10 ) &&
+ !FStrEq( killedwith, "pschreck" ) &&
+ !FStrEq( killedwith, "bazooka" ) )
+ {
+ m_flLastKillTime = 0;
+ return;
+ }
+
+ if ( ( gpGlobals->curtime - m_flLastKillTime ) > 0.25 )
+ {
+ m_iKillCount = 0;
+ }
+
+ m_iKillCount++;
+ m_flLastKillTime = gpGlobals->curtime;
+
+ if ( m_iKillCount == 4 )
+ {
+ IncrementCount();
+ }
+ }
+ }
+
+private:
+ float m_flLastKillTime;
+ int m_iKillCount;
+};
+DECLARE_ACHIEVEMENT( CAchievementDODKillsWithGrenade, ACHIEVEMENT_DOD_KILLS_WITH_GRENADE, "DOD_KILLS_WITH_GRENADE", 1 );
+
+
+class CAchievementDODLongRangeRocket : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+
+ // Handled on server
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODLongRangeRocket, ACHIEVEMENT_DOD_LONG_RANGE_ROCKET, "DOD_LONG_RANGE_ROCKET", 1 );
+
+
+class CAchievementDODEndRoundKills : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+
+ m_iKillCount = 0;
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "player_spawn" );
+ }
+
+ // Reset the count when we spawn
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ if ( m_iKillCount > 0 && 0 == Q_strcmp( event->GetName(), "player_spawn" ) && C_BasePlayer::GetLocalPlayer() )
+ {
+ int iUserID = event->GetInt("userid");
+
+ if ( iUserID == C_BasePlayer::GetLocalPlayer()->GetUserID() )
+ {
+ m_iKillCount = 0;
+ }
+ }
+ }
+
+ // count kills in endround. No requirement that your team must have won the round - grenades count
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ DODRoundState state = DODGameRules()->State_Get();
+
+ if ( state == STATE_ALLIES_WIN || state == STATE_AXIS_WIN )
+ {
+ Assert( pAttacker == C_BasePlayer::GetLocalPlayer() );
+
+ if ( pVictim->GetTeamNumber() != pAttacker->GetTeamNumber() )
+ {
+ m_iKillCount++;
+
+ if ( m_iKillCount > 3 )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+
+ int m_iKillCount;
+};
+DECLARE_ACHIEVEMENT( CAchievementDODEndRoundKills, ACHIEVEMENT_DOD_END_ROUND_KILLS, "DOD_END_ROUND_KILLS", 1 );
+
+
+class CAchievementDODCapLastFlag : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+
+ // handled on server
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODCapLastFlag, ACHIEVEMENT_DOD_CAP_LAST_FLAG, "DOD_CAP_LAST_FLAG", 1 );
+
+
+class CAchievementDODUseEnemyWeapons : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+ }
+
+ // Handled on server
+};
+DECLARE_ACHIEVEMENT( CAchievementDODUseEnemyWeapons, ACHIEVEMENT_DOD_USE_ENEMY_WEAPONS, "DOD_USE_ENEMY_WEAPONS", 1 );
+
+
+class CAchievementDODKillDominatingMG : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+
+ // Handled on server
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODKillDominatingMG, ACHIEVEMENT_DOD_KILL_DOMINATING_MG, "DOD_KILL_DOMINATING_MG", 1 );
+
+
+class CAchievementDODColmarDefense : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+
+ // Handled on server
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODColmarDefense, ACHIEVEMENT_DOD_COLMAR_DEFENSE, "DOD_COLMAR_DEFENSE", 1 );
+
+
+class CAchievementDODJagdOvertimeCap : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+
+ // Handled on server
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODJagdOvertimeCap, ACHIEVEMENT_DOD_JAGD_OVERTIME_CAP, "DOD_JAGD_OVERTIME_CAP", 1 );
+
+
+class CAchievementDODWeaponMastery : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+
+ // Handled on server
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODWeaponMastery, ACHIEVEMENT_DOD_WEAPON_MASTERY, "DOD_WEAPON_MASTERY", 1 );
+
+
+class CAchievementDODBlockCaptures : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "dod_capture_blocked" );
+ }
+
+ // New achievement rule - block a capture that would have lost the game for your team
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ if ( !GameRulesAllowsAchievements() )
+ return;
+
+ Assert( FStrEq( event->GetName(), "dod_capture_blocked" ) );
+
+ // was a blocked defuse or plant, don't count
+ if ( event->GetBool("bomb") )
+ return;
+
+ if ( !g_pObjectiveResource )
+ return;
+
+ C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
+
+ if ( pPlayer && pPlayer->entindex() == event->GetInt("blocker") )
+ {
+ int iCP = event->GetInt( "cp" );
+
+ bool bIsLastOwnedPoint = true;
+
+ int iPlayerTeam = pPlayer->GetTeamNumber();
+
+ for( int i=0;i<g_pObjectiveResource->GetNumControlPoints();i++ )
+ {
+ // assume we own the one we blocked
+ if ( i == iCP )
+ continue;
+
+ // if we find any other points owned by us that aren't hidden, this wasn't the last point
+
+ if( !g_pObjectiveResource->IsCPVisible(i) )
+ continue;
+
+ if ( g_pObjectiveResource->GetOwningTeam(i) == iPlayerTeam )
+ {
+ bIsLastOwnedPoint = false;
+ break;
+ }
+ }
+
+ if ( bIsLastOwnedPoint )
+ {
+ IncrementCount();
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODBlockCaptures, ACHIEVEMENT_DOD_BLOCK_CAPTURES, "DOD_BLOCK_CAPTURES", 1 );
+
+
+// achievements part deux
+
+// kills as allies
+// kills as axis
+class CBaseAchievementKillsOnTeam : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
+ SetGoal( 5000 );
+ SetStoreProgressInSteam( true );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ Assert( pAttacker == C_BasePlayer::GetLocalPlayer() );
+
+ if ( pVictim->GetTeamNumber() != pAttacker->GetTeamNumber() )
+ {
+ if ( pAttacker->GetTeamNumber() == GetTeam() )
+ {
+ IncrementCount();
+ }
+ }
+ }
+
+ virtual int GetTeam( void ) = 0;
+};
+
+class CAchievementKillsAsAllies : public CBaseAchievementKillsOnTeam
+{
+ virtual int GetTeam( void ) { return TEAM_ALLIES; }
+};
+DECLARE_ACHIEVEMENT( CAchievementKillsAsAllies, ACHIEVEMENT_DOD_KILLS_AS_ALLIES, "DOD_KILLS_AS_ALLIES", 1 );
+
+class CAchievementKillsAsAxis : public CBaseAchievementKillsOnTeam
+{
+ virtual int GetTeam( void ) { return TEAM_AXIS; }
+};
+DECLARE_ACHIEVEMENT( CAchievementKillsAsAxis, ACHIEVEMENT_DOD_KILLS_AS_AXIS, "DOD_KILLS_AS_AXIS", 1 );
+
+// rifleman
+// assault
+// support
+// sniper
+// mg
+// bazooka
+class CBaseAchievementKillsAsClass : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
+ SetGoal( 1000 );
+ SetStoreProgressInSteam( true );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ Assert( pAttacker == C_BasePlayer::GetLocalPlayer() );
+
+ if ( pVictim->GetTeamNumber() != pAttacker->GetTeamNumber() )
+ {
+ C_DODPlayer *pDODAttacker = ToDODPlayer( pAttacker );
+
+ if ( pDODAttacker->m_Shared.PlayerClass() == GetClass() )
+ {
+ IncrementCount();
+ }
+ }
+ }
+
+ virtual int GetClass( void ) = 0;
+};
+
+#define DECLARE_KILLS_AS_CLASS_ACHIEVEMENT( classIndex, achievementID ) \
+class CAchievement_##achievementID : public CBaseAchievementKillsAsClass \
+{ \
+ virtual int GetClass( void ) { return classIndex; } \
+}; \
+DECLARE_ACHIEVEMENT( CAchievement_##achievementID, ACHIEVEMENT_##achievementID, #achievementID, 1 ) \
+
+DECLARE_KILLS_AS_CLASS_ACHIEVEMENT( 0, DOD_KILLS_AS_RIFLEMAN );
+DECLARE_KILLS_AS_CLASS_ACHIEVEMENT( 1, DOD_KILLS_AS_ASSAULT );
+DECLARE_KILLS_AS_CLASS_ACHIEVEMENT( 2, DOD_KILLS_AS_SUPPORT );
+DECLARE_KILLS_AS_CLASS_ACHIEVEMENT( 3, DOD_KILLS_AS_SNIPER );
+DECLARE_KILLS_AS_CLASS_ACHIEVEMENT( 4, DOD_KILLS_AS_MG );
+DECLARE_KILLS_AS_CLASS_ACHIEVEMENT( 5, DOD_KILLS_AS_BAZOOKAGUY );
+
+// per weapon
+class CBaseAchievementKillsWithWeapon : public CBaseAchievement
+{
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ Assert( pAttacker == C_BasePlayer::GetLocalPlayer() );
+
+ if ( pVictim->GetTeamNumber() != pAttacker->GetTeamNumber() && event != NULL )
+ {
+ if ( FStrEq( event->GetString( "weapon", "" ), GetWeaponName() ) )
+ {
+ IncrementCount();
+ }
+ }
+ }
+
+ virtual const char *GetWeaponName( void ) = 0;
+};
+
+#define DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( weaponName, goalKills, achievementID ) \
+class CAchievement_##achievementID : public CBaseAchievementKillsWithWeapon \
+{ \
+ void Init() \
+ { \
+ SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL ); \
+ SetGoal( goalKills ); \
+ SetStoreProgressInSteam( true ); \
+ } \
+ \
+ virtual const char *GetWeaponName( void ) { return weaponName; } \
+}; \
+DECLARE_ACHIEVEMENT( CAchievement_##achievementID, ACHIEVEMENT_##achievementID, #achievementID, 1 ) \
+
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "garand", 500, DOD_KILLS_WITH_GARAND );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "thompson", 500, DOD_KILLS_WITH_THOMPSON );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "bar", 500, DOD_KILLS_WITH_BAR );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "spring", 500, DOD_KILLS_WITH_SPRING );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "30cal", 500, DOD_KILLS_WITH_30CAL );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "bazooka", 500, DOD_KILLS_WITH_BAZOOKA );
+
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "k98", 500, DOD_KILLS_WITH_K98 );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "mp40", 500, DOD_KILLS_WITH_MP40 );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "mp44", 500, DOD_KILLS_WITH_MP44 );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "k98_scoped", 500, DOD_KILLS_WITH_K98SCOPED );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "mg42", 500, DOD_KILLS_WITH_MG42 );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "pschreck", 500, DOD_KILLS_WITH_PSCHRECK );
+
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "colt", 150, DOD_KILLS_WITH_COLT );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "p38", 150, DOD_KILLS_WITH_P38 );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "c96", 150, DOD_KILLS_WITH_C96 );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "m1carbine", 150, DOD_KILLS_WITH_M1CARBINE );
+
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "amerknife", 150, DOD_KILLS_WITH_AMERKNIFE );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "spade", 150, DOD_KILLS_WITH_SPADE );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "punch", 150, DOD_KILLS_WITH_PUNCH );
+
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "frag_us", 250, DOD_KILLS_WITH_FRAG_US );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "frag_ger", 250, DOD_KILLS_WITH_FRAG_GER );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "riflegren_us", 250, DOD_KILLS_WITH_RIFLEGREN_US );
+DECLARE_KILLS_WITH_WEAPON_ACHIEVEMENT( "riflegren_ger", 250, DOD_KILLS_WITH_RIFLEGREN_GER );
+
+
+// flag captures
+class CAchievementDODFlagCaptureGrind : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 100 );
+ SetStoreProgressInSteam( true );
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "dod_point_captured" );
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ Assert( FStrEq( event->GetName(), "dod_point_captured" ) );
+
+ if ( event->GetBool( "bomb" ) == true )
+ return;
+
+ if ( !GameRulesAllowsAchievements() )
+ return;
+
+ C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
+ if ( !pPlayer )
+ return;
+
+ int iLocalPlayerIndex = pPlayer->entindex();
+
+ const char *cappers = event->GetString("cappers");
+
+ int len = Q_strlen(cappers);
+ for( int i=0;i<len;i++ )
+ {
+ if ( iLocalPlayerIndex == (int)cappers[i] )
+ {
+ IncrementCount();
+ break;
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODFlagCaptureGrind, ACHIEVEMENT_DOD_CAPTURE_GRIND, "DOD_CAPTURE_GRIND", 1 );
+
+
+class CAchievementDODBlockCapturesGrind : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 100 );
+ SetStoreProgressInSteam( true );
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "dod_capture_blocked" );
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ if ( !GameRulesAllowsAchievements() )
+ return;
+
+ Assert( FStrEq( event->GetName(), "dod_capture_blocked" ) );
+
+ if ( event->GetBool( "bomb" ) )
+ return;
+
+ C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
+
+ if ( pPlayer && pPlayer->entindex() == event->GetInt( "blocker" ) )
+ {
+ IncrementCount();
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODBlockCapturesGrind, ACHIEVEMENT_DOD_BLOCK_CAPTURES_GRIND, "DOD_BLOCK_CAPTURES_GRIND", 1 );
+
+
+class CAchievementDODRoundsWonGrind : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 100 );
+ SetStoreProgressInSteam( true );
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "dod_round_win" );
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ if ( !GameRulesAllowsAchievements() )
+ return;
+
+ Assert( FStrEq( event->GetName(), "dod_round_win" ) );
+
+ C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
+ if ( !pPlayer )
+ return;
+
+ if ( event->GetInt( "team" ) == pPlayer->GetTeamNumber() )
+ {
+ IncrementCount();
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODRoundsWonGrind, ACHIEVEMENT_DOD_ROUNDS_WON_GRIND, "DOD_ROUNDS_WON_GRIND", 1 );
+
+
+class CAchievementDODBombsPlantedGrind : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 100 );
+ SetStoreProgressInSteam( true );
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "dod_bomb_planted" );
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ Assert( FStrEq( event->GetName(), "dod_bomb_planted" ) );
+
+ C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
+
+ if ( pPlayer && pPlayer->GetUserID() == event->GetInt("userid" ) )
+ {
+ IncrementCount();
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODBombsPlantedGrind, ACHIEVEMENT_DOD_BOMBS_PLANTED_GRIND, "DOD_BOMBS_PLANTED_GRIND", 1 );
+
+
+class CAchievementDODBombsDefusedGrind : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 100 );
+ SetStoreProgressInSteam( true );
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "dod_bomb_defused" );
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ Assert( FStrEq( event->GetName(), "dod_bomb_defused" ) );
+
+ if ( event->GetInt("userid") == C_BasePlayer::GetLocalPlayer()->GetUserID() )
+ {
+ IncrementCount();
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODBombsDefusedGrind, ACHIEVEMENT_DOD_BOMBS_DEFUSED_GRIND, "DOD_BOMBS_DEFUSED_GRIND", 1 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementDOD_All_Pack_1 : public CAchievement_AchievedCount
+{
+public:
+ DECLARE_CLASS( CAchievementDOD_All_Pack_1, CAchievement_AchievedCount );
+ void Init()
+ {
+ BaseClass::Init();
+ SetAchievementsRequired( 51, 0, 51 );
+ }
+
+ // Complete all dod achievements
+};
+DECLARE_ACHIEVEMENT( CAchievementDOD_All_Pack_1, ACHIEVEMENT_DOD_ALL_PACK_1, "DOD_ALL_PACK_1", 5 );
+
+
+// 2011 Summer sale achievement
+// Win a round on each of the winter themed maps, dod_kalt and dod_colmar
+// player is not required to have been present at the start of the round
+class CAchievementDODBeatTheHeat : public CBaseAchievement
+{
+public:
+ DECLARE_CLASS( CAchievementDODBeatTheHeat, CBaseAchievement );
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_HAS_COMPONENTS );
+
+ static const char *szComponents[] =
+ {
+ "dod_kalt", "dod_colmar"
+ };
+ m_pszComponentNames = szComponents;
+ m_iNumComponents = ARRAYSIZE( szComponents );
+ SetGoal( m_iNumComponents );
+
+ BaseClass::Init();
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "dod_round_win" );
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ if ( !GameRulesAllowsAchievements() )
+ return;
+
+ Assert( FStrEq( event->GetName(), "dod_round_win" ) );
+
+ C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
+ if ( !pPlayer )
+ return;
+
+ if ( event->GetInt( "team" ) == pPlayer->GetTeamNumber() )
+ {
+ OnComponentEvent( m_pAchievementMgr->GetMapName() );
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODBeatTheHeat, ACHIEVEMENT_DOD_BEAT_THE_HEAT, "DOD_BEAT_THE_HEAT", 1 );
+
+// Winter 2011
+class CAchievementDODCollectHolidayGifts : public CBaseAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 3 );
+ SetStoreProgressInSteam( true );
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "christmas_gift_grab" );
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ // if ( !UTIL_IsHolidayActive( kHoliday_Christmas ) )
+ // return;
+
+ if ( Q_strcmp( event->GetName(), "christmas_gift_grab" ) == 0 )
+ {
+ int iPlayer = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
+ CBaseEntity *pPlayer = UTIL_PlayerByIndex( iPlayer );
+
+ if ( pPlayer && pPlayer == C_DODPlayer::GetLocalDODPlayer() )
+ {
+ IncrementCount();
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementDODCollectHolidayGifts, ACHIEVEMENT_DOD_COLLECT_HOLIDAY_GIFTS, "DOD_COLLECT_HOLIDAY_GIFTS", 5 );
+
+#endif // CLIENT_DLL \ No newline at end of file
diff --git a/game/shared/dod/dod_gamemovement.cpp b/game/shared/dod/dod_gamemovement.cpp
new file mode 100644
index 0000000..9582189
--- /dev/null
+++ b/game/shared/dod/dod_gamemovement.cpp
@@ -0,0 +1,1405 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+//========= Copyright � 1996-2001, Valve LLC, All rights reserved. ============
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+#include "cbase.h"
+#include "gamemovement.h"
+#include "dod_gamerules.h"
+#include "dod_shareddefs.h"
+#include "in_buttons.h"
+#include "movevars_shared.h"
+
+#include "weapon_dodsniper.h"
+#include "weapon_dodbaserpg.h"
+#include "weapon_dodsemiauto.h"
+
+
+#ifdef CLIENT_DLL
+ #include "c_dod_player.h"
+#else
+ #include "dod_player.h"
+#endif
+
+extern bool g_bMovementOptimizations;
+
+class CDODGameMovement : public CGameMovement
+{
+public:
+ DECLARE_CLASS( CDODGameMovement, CGameMovement );
+
+ CDODGameMovement();
+ virtual ~CDODGameMovement();
+
+ void SetPlayerSpeed( void );
+
+ virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove );
+ virtual bool CanAccelerate();
+ virtual bool CheckJumpButton( void );
+ virtual void ReduceTimers( void );
+ virtual void WalkMove( void );
+ virtual void AirMove( void );
+ virtual void CheckParameters( void );
+ virtual void CheckFalling( void );
+
+ // Ducking
+ virtual void Duck( void );
+ virtual void FinishUnDuck( void );
+ virtual void FinishDuck( void );
+ virtual void HandleDuckingSpeedCrop();
+ void SetDODDuckedEyeOffset( float duckFraction );
+ void SetDeployedEyeOffset( void );
+
+ // Prone
+ void SetProneEyeOffset( float proneFraction );
+ void FinishProne( void );
+ void FinishUnProne( void );
+ bool CanUnprone();
+
+ virtual Vector GetPlayerMins( void ) const; // uses local player
+ virtual Vector GetPlayerMaxs( void ) const; // uses local player
+
+ // IGameMovement interface
+ virtual Vector GetPlayerMins( bool ducked ) const { return BaseClass::GetPlayerMins(ducked); }
+ virtual Vector GetPlayerMaxs( bool ducked ) const { return BaseClass::GetPlayerMaxs(ducked); }
+ virtual Vector GetPlayerViewOffset( bool ducked ) const { return BaseClass::GetPlayerViewOffset(ducked); }
+
+ void ViewOffsetAnimation( Vector vecDest, float flTime, ViewAnimationType type );
+
+ void SetViewOffset( Vector vecViewOffset );
+
+ virtual unsigned int PlayerSolidMask( bool brushOnly = false );
+
+protected:
+ virtual void PlayerMove();
+
+ void CheckForLadders( bool wasOnGround );
+ bool ResolveStanding( void );
+ void TracePlayerBBoxWithStep( const Vector &vStart, const Vector &vEnd, unsigned int fMask, int collisionGroup, trace_t &trace );
+
+public:
+ CDODPlayer *m_pDODPlayer;
+ bool m_bUnProneToDuck;
+};
+
+
+// Expose our interface.
+static CDODGameMovement g_GameMovement;
+IGameMovement *g_pGameMovement = ( IGameMovement * )&g_GameMovement;
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameMovement, IGameMovement,INTERFACENAME_GAMEMOVEMENT, g_GameMovement );
+
+
+// ---------------------------------------------------------------------------------------- //
+// CDODGameMovement.
+// ---------------------------------------------------------------------------------------- //
+
+CDODGameMovement::CDODGameMovement()
+{
+ // Don't set any member variables here, or you'll get an access
+ // violation exception on LoadLibrary, and will have to stay up til
+ // 3 in the morning figuring out where you did bad things.
+
+ m_bUnProneToDuck = false;
+}
+
+CDODGameMovement::~CDODGameMovement()
+{
+}
+
+void CDODGameMovement::SetPlayerSpeed( void )
+{
+ if( DODGameRules()->State_Get() == STATE_PREROUND )
+ {
+ mv->m_flClientMaxSpeed = PLAYER_SPEED_FROZEN;
+ return;
+ }
+
+ if ( m_pDODPlayer->m_Shared.IsPlanting() ||
+ m_pDODPlayer->m_Shared.IsDefusing() )
+ {
+ mv->m_flClientMaxSpeed = PLAYER_SPEED_FROZEN;
+ return;
+ }
+
+ bool bZoomed = ( m_pDODPlayer->GetFOV() < m_pDODPlayer->GetDefaultFOV() );
+ bool bBazookaDeployed = false;
+ bool bZoomingIn = false;
+
+ CWeaponDODBase *pWpn = m_pDODPlayer->GetActiveDODWeapon();
+ if( pWpn )
+ {
+ if( pWpn->GetDODWpnData().m_WeaponType == WPN_TYPE_BAZOOKA )
+ {
+ CDODBaseRocketWeapon *pBazooka = (CDODBaseRocketWeapon *)pWpn;
+ bBazookaDeployed = pBazooka->ShouldPlayerBeSlow();
+ }
+
+ if ( pWpn->GetDODWpnData().m_WeaponType == WPN_TYPE_SNIPER )
+ {
+ CDODSniperWeapon *pSniper = dynamic_cast<CDODSniperWeapon *>( pWpn );
+ if ( pSniper )
+ {
+ bZoomingIn = !bZoomed && pSniper->IsZoomingIn();
+ }
+ }
+ }
+
+ // are we zooming?
+
+ if ( m_pDODPlayer->m_Shared.IsInMGDeploy() )
+ {
+ mv->m_flClientMaxSpeed = PLAYER_SPEED_FROZEN;
+ }
+ else if ( m_pDODPlayer->m_Shared.IsProne() &&
+ !m_pDODPlayer->m_Shared.IsGettingUpFromProne() &&
+ m_pDODPlayer->GetGroundEntity() != NULL )
+ {
+ if ( bZoomed )
+ mv->m_flClientMaxSpeed = PLAYER_SPEED_PRONE_ZOOMED;
+ else if ( bBazookaDeployed )
+ mv->m_flClientMaxSpeed = PLAYER_SPEED_PRONE_BAZOOKA_DEPLOYED;
+ else
+ mv->m_flClientMaxSpeed = PLAYER_SPEED_PRONE; //Base prone speed
+ }
+ else //not prone, dead or deployed - standing or crouching and possibly moving
+ {
+ float stamina = m_pDODPlayer->m_Shared.GetStamina();
+
+ if ( bZoomed )
+ {
+ mv->m_flClientMaxSpeed = PLAYER_SPEED_ZOOMED;
+ }
+ else if ( bBazookaDeployed )
+ {
+ mv->m_flClientMaxSpeed = PLAYER_SPEED_BAZOOKA_DEPLOYED;
+ }
+ else if ( mv->m_nButtons & IN_DUCK )
+ {
+ mv->m_flClientMaxSpeed = PLAYER_SPEED_RUN; //gets cut in fraction later
+ }
+ // check for slowed from leg hit or firing a machine gun
+ else if ( m_pDODPlayer->m_Shared.GetSlowedTime() > gpGlobals->curtime )
+ {
+ mv->m_flClientMaxSpeed = PLAYER_SPEED_SLOWED;
+ }
+ else
+ {
+ float flMaxSpeed;
+
+ if ( ( mv->m_nButtons & IN_SPEED ) && ( stamina > 0 ) && ( mv->m_nButtons & IN_FORWARD ) && !bZoomingIn )
+ {
+ flMaxSpeed = PLAYER_SPEED_SPRINT; //sprinting
+ }
+ else
+ {
+ flMaxSpeed = PLAYER_SPEED_RUN; //jogging
+ }
+
+ mv->m_flClientMaxSpeed = flMaxSpeed - 100 + stamina;
+ }
+ }
+
+ if ( m_pDODPlayer->GetGroundEntity() != NULL )
+ {
+ if( m_pDODPlayer->m_Shared.IsGoingProne() )
+ {
+ float pronetime = m_pDODPlayer->m_Shared.m_flGoProneTime - gpGlobals->curtime;
+
+ //interp to prone speed
+ float flProneFraction = SimpleSpline( pronetime / TIME_TO_PRONE );
+
+ float maxSpeed = mv->m_flClientMaxSpeed;
+
+ if ( m_bUnProneToDuck )
+ maxSpeed *= 0.33;
+
+ mv->m_flClientMaxSpeed = ( ( 1 - flProneFraction ) * PLAYER_SPEED_PRONE ) + ( flProneFraction * maxSpeed );
+ }
+ else if( m_pDODPlayer->m_Shared.IsGettingUpFromProne() )
+ {
+ float pronetime = m_pDODPlayer->m_Shared.m_flUnProneTime - gpGlobals->curtime;
+
+ //interp to regular speed speed
+ float flProneFraction = SimpleSpline( pronetime / TIME_TO_PRONE );
+
+ float maxSpeed = mv->m_flClientMaxSpeed;
+
+ if ( m_bUnProneToDuck )
+ maxSpeed *= 0.33;
+
+ mv->m_flClientMaxSpeed = ( flProneFraction * PLAYER_SPEED_PRONE ) + ( ( 1 - flProneFraction ) * maxSpeed );
+ }
+ }
+}
+
+ConVar cl_show_speed( "cl_show_speed", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "spam console with local player speed" );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDODGameMovement::CheckParameters( void )
+{
+ QAngle v_angle;
+
+ SetPlayerSpeed();
+
+ if ( player->GetMoveType() != MOVETYPE_ISOMETRIC &&
+ player->GetMoveType() != MOVETYPE_NOCLIP &&
+ player->GetMoveType() != MOVETYPE_OBSERVER )
+ {
+ float spd;
+ float maxspeed;
+
+ spd = ( mv->m_flForwardMove * mv->m_flForwardMove ) +
+ ( mv->m_flSideMove * mv->m_flSideMove ) +
+ ( mv->m_flUpMove * mv->m_flUpMove );
+
+ maxspeed = mv->m_flClientMaxSpeed;
+ if ( maxspeed != 0.0 )
+ {
+ mv->m_flMaxSpeed = MIN( maxspeed, mv->m_flMaxSpeed );
+ }
+
+ // Slow down by the speed factor
+ float flSpeedFactor = 1.0f;
+ if ( player->GetSurfaceData() )
+ {
+ flSpeedFactor = player->GetSurfaceData()->game.maxSpeedFactor;
+ }
+
+ // If we have a constraint, slow down because of that too.
+ float flConstraintSpeedFactor = ComputeConstraintSpeedFactor();
+ if (flConstraintSpeedFactor < flSpeedFactor)
+ flSpeedFactor = flConstraintSpeedFactor;
+
+ mv->m_flMaxSpeed *= flSpeedFactor;
+
+ if ( g_bMovementOptimizations )
+ {
+ // Same thing but only do the sqrt if we have to.
+ if ( ( spd != 0.0 ) && ( spd > mv->m_flMaxSpeed*mv->m_flMaxSpeed ) )
+ {
+ float fRatio = mv->m_flMaxSpeed / sqrt( spd );
+ mv->m_flForwardMove *= fRatio;
+ mv->m_flSideMove *= fRatio;
+ mv->m_flUpMove *= fRatio;
+ }
+ }
+ else
+ {
+ spd = sqrt( spd );
+ if ( ( spd != 0.0 ) && ( spd > mv->m_flMaxSpeed ) )
+ {
+ float fRatio = mv->m_flMaxSpeed / spd;
+ mv->m_flForwardMove *= fRatio;
+ mv->m_flSideMove *= fRatio;
+ mv->m_flUpMove *= fRatio;
+ }
+ }
+ }
+
+
+ if ( player->GetFlags() & FL_FROZEN ||
+ player->GetFlags() & FL_ONTRAIN ||
+ IsDead() )
+ {
+ mv->m_flForwardMove = 0;
+ mv->m_flSideMove = 0;
+ mv->m_flUpMove = 0;
+ }
+
+ DecayPunchAngle();
+
+ // Take angles from command.
+ if ( !IsDead() )
+ {
+ v_angle = mv->m_vecAngles;
+ v_angle = v_angle + player->m_Local.m_vecPunchAngle;
+
+ // Now adjust roll angle
+ if ( player->GetMoveType() != MOVETYPE_ISOMETRIC &&
+ player->GetMoveType() != MOVETYPE_NOCLIP )
+ {
+ mv->m_vecAngles[ROLL] = CalcRoll( v_angle, mv->m_vecVelocity, sv_rollangle.GetFloat(), sv_rollspeed.GetFloat() );
+ }
+ else
+ {
+ mv->m_vecAngles[ROLL] = 0.0; // v_angle[ ROLL ];
+ }
+ mv->m_vecAngles[PITCH] = v_angle[PITCH];
+ mv->m_vecAngles[YAW] = v_angle[YAW];
+ }
+ else
+ {
+ mv->m_vecAngles = mv->m_vecOldAngles;
+ }
+
+ // Set dead player view_offset
+ if ( IsDead() )
+ {
+ SetViewOffset( VEC_DEAD_VIEWHEIGHT_SCALED( player ) );
+ }
+
+ // Adjust client view angles to match values used on server.
+ if ( mv->m_vecAngles[YAW] > 180.0f )
+ {
+ mv->m_vecAngles[YAW] -= 360.0f;
+ }
+
+ if ( cl_show_speed.GetBool() )
+ {
+ Vector vel = m_pDODPlayer->GetAbsVelocity();
+ float actual_speed = sqrt( vel.x * vel.x + vel.y * vel.y );
+ Msg( "player speed %.1f\n",actual_speed );
+ }
+}
+
+void CDODGameMovement::CheckFalling( void )
+{
+ // if we landed on the ground
+ if ( player->GetGroundEntity() != NULL && !IsDead() )
+ {
+ if ( player->m_Local.m_flFallVelocity >= 300 )
+ {
+ CPASFilter filter( player->GetAbsOrigin() );
+ filter.UsePredictionRules();
+ player->EmitSound( filter, player->entindex(), "Player.JumpLanding" );
+ }
+
+ // turn off the jumping flag if we're on ground after a jump
+ if ( m_pDODPlayer->m_Shared.IsJumping() )
+ {
+ m_pDODPlayer->m_Shared.SetJumping( false );
+
+ // if we landed from a jump, slow us
+ if ( player->m_Local.m_flFallVelocity > 50 )
+ m_pDODPlayer->m_Shared.SetSlowedTime( 0.5 );
+ }
+ }
+
+ BaseClass::CheckFalling();
+}
+
+
+void CDODGameMovement::ProcessMovement( CBasePlayer *pBasePlayer, CMoveData *pMove )
+{
+ //Store the player pointer
+ m_pDODPlayer = ToDODPlayer( pBasePlayer );
+ Assert( m_pDODPlayer );
+
+ m_pDODPlayer->m_Shared.ViewAnimThink();
+
+ BaseClass::ProcessMovement( pBasePlayer, pMove );
+}
+
+bool CDODGameMovement::CanAccelerate()
+{
+ // Only allow the player to accelerate when in certain states.
+ DODPlayerState curState = m_pDODPlayer->State_Get();
+ if ( curState == STATE_ACTIVE )
+ {
+ return player->GetWaterJumpTime() == 0;
+ }
+ else if ( player->IsObserver() )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void CDODGameMovement::PlayerMove()
+{
+ BaseClass::PlayerMove();
+
+ if ( player->GetMoveType() != MOVETYPE_ISOMETRIC &&
+ player->GetMoveType() != MOVETYPE_NOCLIP &&
+ player->GetMoveType() != MOVETYPE_OBSERVER )
+ {
+
+ // Cap actual player speed, fix wall running
+ float spd = mv->m_vecVelocity[0] * mv->m_vecVelocity[0] +
+ mv->m_vecVelocity[1] * mv->m_vecVelocity[1];
+
+ if( spd > 0.0 && spd > ( mv->m_flMaxSpeed * mv->m_flMaxSpeed ) )
+ {
+ float fRatio = mv->m_flMaxSpeed / sqrt( spd );
+ mv->m_vecVelocity[0] *= fRatio;
+ mv->m_vecVelocity[1] *= fRatio;
+ }
+ }
+}
+
+
+void CDODGameMovement::WalkMove( void )
+{
+ float flSpeed = m_pDODPlayer->GetAbsVelocity().Length2D();
+
+ bool bSprintButtonPressed = ( mv->m_nButtons & IN_SPEED ) > 0;
+
+ if( bSprintButtonPressed &&
+ ( mv->m_nButtons & IN_FORWARD ) &&
+ !m_pDODPlayer->m_Shared.IsProne() &&
+ !m_pDODPlayer->m_Shared.IsDucking() &&
+ flSpeed > 80 )
+ {
+ m_pDODPlayer->SetSprinting( true );
+ }
+ else
+ {
+ m_pDODPlayer->SetSprinting( false );
+ }
+
+ BaseClass::WalkMove();
+
+ //CheckForLadders( true );
+ //ResolveStanding();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Allow bots etc to use slightly different solid masks
+//-----------------------------------------------------------------------------
+unsigned int CDODGameMovement::PlayerSolidMask( bool brushOnly )
+{
+ int mask = 0;
+
+ switch ( m_pDODPlayer->GetTeamNumber() )
+ {
+ case TEAM_ALLIES:
+ mask = CONTENTS_TEAM1;
+ break;
+
+ case TEAM_AXIS:
+ mask = CONTENTS_TEAM2;
+ break;
+ }
+
+ return ( mask | BaseClass::PlayerSolidMask( brushOnly ) );
+}
+
+void CDODGameMovement::AirMove( void )
+{
+ BaseClass::AirMove();
+
+ //CheckForLadders( false );
+}
+
+void CDODGameMovement::CheckForLadders( bool wasOnGround )
+{
+ if ( !wasOnGround || !ResolveStanding() )
+ {
+ trace_t trace;
+ TracePlayerBBox( mv->GetAbsOrigin(), mv->GetAbsOrigin() + Vector( 0, 0, -5), MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace );
+ if ( trace.fraction == 1.0f )
+ {
+ Vector vel = -m_pDODPlayer->m_lastStandingPos + mv->GetAbsOrigin();
+ if ( !vel.x && !vel.y )
+ {
+ return;
+ }
+ vel.NormalizeInPlace();
+ vel *= 5.0f;
+ Vector vecStartPos( mv->GetAbsOrigin().x + vel.x, mv->GetAbsOrigin().y + vel.y, mv->GetAbsOrigin().z );
+ vel *= 5.0f;
+ Vector vecStandPos( mv->GetAbsOrigin().x - vel.x, mv->GetAbsOrigin().y - vel.y, mv->GetAbsOrigin().z - ( player->m_Local.m_flStepSize * 1.0f ) );
+
+ TracePlayerBBoxWithStep( vecStartPos, vecStandPos, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace );
+
+ if ( trace.fraction != 1.0f && OnLadder( trace ) && trace.plane.normal.z != 1.0f )
+ {
+ if ( trace.fraction > 0.6 )
+ {
+ vel.NormalizeInPlace();
+ Vector org = mv->GetAbsOrigin();
+ org -= vel*5;
+ mv->SetAbsOrigin( org );
+ }
+ player->SetMoveType( MOVETYPE_LADDER );
+ player->SetMoveCollide( MOVECOLLIDE_DEFAULT );
+
+ player->SetLadderNormal( trace.plane.normal );
+ mv->m_vecVelocity.Init();
+ }
+ }
+ }
+ else
+ {
+ m_pDODPlayer->m_lastStandingPos = mv->GetAbsOrigin();
+ }
+}
+
+inline void CDODGameMovement::TracePlayerBBoxWithStep( const Vector &vStart, const Vector &vEnd,
+ unsigned int fMask, int collisionGroup, trace_t &trace )
+{
+ VPROF( "CDODGameMovement::TracePlayerBBoxWithStep" );
+
+ Vector vHullMin = GetPlayerMins( player->m_Local.m_bDucked );
+ vHullMin.z += player->m_Local.m_flStepSize;
+ Vector vHullMax = GetPlayerMaxs( player->m_Local.m_bDucked );
+
+ Ray_t ray;
+ ray.Init( vStart, vEnd, vHullMin, vHullMax );
+ UTIL_TraceRay( ray, fMask, mv->m_nPlayerHandle.Get(), collisionGroup, &trace );
+}
+
+// Taken from TF2 to prevent bouncing down slopes
+bool CDODGameMovement::ResolveStanding( void )
+{
+ VPROF( "CDODGameMovement::ResolveStanding" );
+
+ //
+ // Attempt to move down twice your step height. Anything between 0.5 and 1.0
+ // is a valid "stand" value.
+ //
+
+ // Matt - don't move twice your step height, only check a little bit down
+ // this will keep us relatively glued to stairs without feeling too snappy
+ float flMaxStepDrop = 8.0f;
+
+ Vector vecStandPos( mv->GetAbsOrigin().x, mv->GetAbsOrigin().y, mv->GetAbsOrigin().z - ( flMaxStepDrop ) );
+
+ trace_t trace;
+ TracePlayerBBoxWithStep( mv->GetAbsOrigin(), vecStandPos, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace );
+
+ // Anything between 0.5 and 1.0 is a valid stand value
+ if ( fabs( trace.fraction - 0.5 ) < 0.0004f )
+ {
+ return true;
+ }
+
+ if ( trace.fraction > 0.5f )
+ {
+ trace.fraction -= 0.5f;
+ Vector vecNewOrigin;
+ vecNewOrigin = mv->GetAbsOrigin() + trace.fraction * ( vecStandPos - mv->GetAbsOrigin() );
+ mv->SetAbsOrigin( vecNewOrigin );
+ return false;
+ }
+
+ // Less than 0.5 mean we need to attempt to push up the difference.
+ vecStandPos.z = ( mv->GetAbsOrigin().z + ( ( 0.5f - trace.fraction ) * ( player->m_Local.m_flStepSize * 2.0f ) ) );
+ TracePlayerBBoxWithStep( mv->GetAbsOrigin(), vecStandPos, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace );
+
+ // A fraction of 1.0 means we stood up fine - done.
+ if ( trace.fraction == 1.0f )
+ {
+ mv->SetAbsOrigin( trace.endpos );
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Recover stamina
+//-----------------------------------------------------------------------------
+void CDODGameMovement::ReduceTimers( void )
+{
+ Vector vecPlayerVelocity = m_pDODPlayer->GetAbsVelocity();
+ float flStamina = m_pDODPlayer->m_Shared.GetStamina();
+ float fl2DVelocitySquared = vecPlayerVelocity.x * vecPlayerVelocity.x +
+ vecPlayerVelocity.y * vecPlayerVelocity.y;
+
+ if ( !( mv->m_nButtons & IN_SPEED ) )
+ {
+ m_pDODPlayer->m_Shared.ResetSprintPenalty();
+ }
+
+ // Can only sprint in forward direction.
+ bool bSprinting = ( (mv->m_nButtons & IN_SPEED) && ( mv->m_nButtons & IN_FORWARD ) );
+
+ // If we're holding the sprint key and also actually moving, remove some stamina
+ Vector vel = m_pDODPlayer->GetAbsVelocity();
+ if ( bSprinting && fl2DVelocitySquared > 10000 ) //speed > 100
+ {
+ //flStamina -= 30 * gpGlobals->frametime; //reduction for sprinting
+ //flStamina += 10 * gpGlobals->frametime; //addition for recovering
+
+ flStamina -= 20 * gpGlobals->frametime;
+
+ m_pDODPlayer->m_Shared.SetStamina( flStamina );
+ }
+ else
+ {
+ //gain some back
+ if ( fl2DVelocitySquared <= 0 )
+ {
+ flStamina += 60 * gpGlobals->frametime;
+ }
+ else if ( ( m_pDODPlayer->GetFlags() & FL_ONGROUND ) &&
+ ( mv->m_nButtons & IN_DUCK ) &&
+ ( m_pDODPlayer->GetFlags() & FL_DUCKING ) )
+ {
+ flStamina += 50 * gpGlobals->frametime;
+ }
+ else
+ {
+ flStamina += 10 * gpGlobals->frametime;
+ }
+
+ m_pDODPlayer->m_Shared.SetStamina( flStamina );
+ }
+
+#ifdef CLIENT_DLL
+ if ( bSprinting && flStamina < 25 )
+ {
+ m_pDODPlayer->HintMessage( HINT_LOW_STAMINA );
+ }
+#endif
+
+ BaseClass::ReduceTimers();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CDODGameMovement::CheckJumpButton( void )
+{
+ if (m_pDODPlayer->pl.deadflag)
+ {
+ mv->m_nOldButtons |= IN_JUMP ; // don't jump again until released
+ return false;
+ }
+
+ if( m_pDODPlayer->m_Shared.IsProne() ||
+ m_pDODPlayer->m_Shared.IsGettingUpFromProne() ||
+ m_pDODPlayer->m_Shared.IsGoingProne() )
+ {
+ mv->m_nOldButtons |= IN_JUMP;
+ return false;
+ }
+
+ // See if we are waterjumping. If so, decrement count and return.
+ float flWaterJumpTime = player->GetWaterJumpTime();
+
+ if ( flWaterJumpTime > 0 )
+ {
+ flWaterJumpTime -= gpGlobals->frametime;
+ if (flWaterJumpTime < 0)
+ flWaterJumpTime = 0;
+
+ player->SetWaterJumpTime( flWaterJumpTime );
+
+ return false;
+ }
+
+ // If we are in the water most of the way...
+ if ( m_pDODPlayer->GetWaterLevel() >= 2 )
+ {
+ // swimming, not jumping
+ SetGroundEntity( NULL );
+
+ if(m_pDODPlayer->GetWaterType() == CONTENTS_WATER) // We move up a certain amount
+ mv->m_vecVelocity[2] = 100;
+ else if (m_pDODPlayer->GetWaterType() == CONTENTS_SLIME)
+ mv->m_vecVelocity[2] = 80;
+
+ // play swiming sound
+ if ( player->GetSwimSoundTime() <= 0 )
+ {
+ // Don't play sound again for 1 second
+ player->SetSwimSoundTime( 1000 );
+ PlaySwimSound();
+ }
+
+ return false;
+ }
+
+ // No more effect
+ if (m_pDODPlayer->GetGroundEntity() == NULL)
+ {
+ mv->m_nOldButtons |= IN_JUMP;
+ return false; // in air, so no effect
+ }
+
+ if ( mv->m_nOldButtons & IN_JUMP )
+ return false; // don't pogo stick
+
+ if( m_pDODPlayer->m_Shared.IsInMGDeploy() )
+ {
+ return false;
+ }
+
+ // In the air now.
+ SetGroundEntity( NULL );
+
+ m_pDODPlayer->PlayStepSound( (Vector &)mv->GetAbsOrigin(), player->GetSurfaceData(), 1.0, true );
+
+ m_pDODPlayer->DoAnimationEvent( PLAYERANIMEVENT_JUMP );
+
+ // make the jump sound
+ CPASFilter filter( m_pDODPlayer->GetAbsOrigin() );
+ filter.UsePredictionRules();
+ m_pDODPlayer->EmitSound( filter, m_pDODPlayer->entindex(), "Player.Jump" );
+
+ float flGroundFactor = 1.0f;
+ if ( player->GetSurfaceData() )
+ {
+ flGroundFactor = player->GetSurfaceData()->game.jumpFactor;
+ }
+
+ /*
+ // old and busted
+
+ float flStamina = m_pDODPlayer->m_Shared.GetStamina();
+
+ //15.0 is the base height. the player will always jump this high
+ //regardless of stamina. Also the player will be able to jump max height
+ //until he is below 60 stamina. Then the height will decrease proportionately
+
+ float flJumpSpeed = 15.0; //base jump height
+
+ if( flStamina >= 60.0f )
+ {
+ flJumpSpeed += 30.0;
+ }
+ else
+ {
+ flJumpSpeed += (30.0 * ( flStamina / 60.0f ) );
+ }
+
+ //Remove stamina for a successful jump
+ m_pDODPlayer->m_Shared.SetStamina( flStamina - 40 );
+
+ */
+
+ // new hotness - constant jumpspeed of 45
+ //m_pDODPlayer->m_Shared.SetSlowedTime( 1.0f );
+
+ Assert( GetCurrentGravity() == 800.0f );
+
+ // Accelerate upward
+ // If we are ducking...
+ float startz = mv->m_vecVelocity[2];
+ if ( ( m_pDODPlayer->m_Local.m_bDucking ) || ( m_pDODPlayer->GetFlags() & FL_DUCKING ) )
+ {
+ // d = 0.5 * g * t^2 - distance traveled with linear accel
+ // t = sqrt(2.0 * 45 / g) - how long to fall 45 units
+ // v = g * t - velocity at the end (just invert it to jump up that high)
+ // v = g * sqrt(2.0 * 45 / g )
+ // v^2 = g * g * 2.0 * 45 / g
+ // v = sqrt( g * 2.0 * 45 )
+
+ mv->m_vecVelocity[2] = flGroundFactor * 268.3281572999747f; // flJumpSpeed of 45
+ //mv->m_vecVelocity[2] = flGroundFactor * sqrt(2 * 800 * flJumpSpeed); // 2 * gravity * height
+ }
+ else
+ {
+ mv->m_vecVelocity[2] += flGroundFactor * 268.3281572999747f; // flJumpSpeed of 45
+ //mv->m_vecVelocity[2] += flGroundFactor * sqrt(2 * 800 * flJumpSpeed); // 2 * gravity * height
+ }
+
+ FinishGravity();
+
+ mv->m_outWishVel.z += mv->m_vecVelocity[2] - startz;
+ mv->m_outStepHeight += 0.1f;
+
+ // Flag that we jumped.
+ mv->m_nOldButtons |= IN_JUMP; // don't jump again until released
+
+ m_pDODPlayer->m_Shared.SetJumping( true );
+
+ return true;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Limit speed if we are ducking
+//-----------------------------------------------------------------------------
+void CDODGameMovement::HandleDuckingSpeedCrop()
+{
+ if ( !( m_iSpeedCropped & SPEED_CROPPED_DUCK ) )
+ {
+ if ( ( mv->m_nButtons & IN_DUCK ) || ( player->m_Local.m_bDucking ) || ( player->GetFlags() & FL_DUCKING ) )
+ {
+ float frac = 0.33333333f;
+ mv->m_flForwardMove *= frac;
+ mv->m_flSideMove *= frac;
+ mv->m_flUpMove *= frac;
+ m_iSpeedCropped |= SPEED_CROPPED_DUCK;
+ }
+ }
+}
+
+bool CDODGameMovement::CanUnprone()
+{
+ int i;
+ trace_t trace;
+ Vector newOrigin;
+
+ VectorCopy( mv->GetAbsOrigin(), newOrigin );
+
+ Vector vecMins, vecMaxs;
+
+ if ( mv->m_nButtons & IN_DUCK )
+ {
+ vecMins = VEC_DUCK_HULL_MIN_SCALED( player );
+ vecMaxs = VEC_DUCK_HULL_MAX_SCALED( player );
+ }
+ else
+ {
+ vecMins = VEC_HULL_MIN_SCALED( player );
+ vecMaxs = VEC_HULL_MAX_SCALED( player );
+ }
+
+ if ( player->GetGroundEntity() != NULL )
+ {
+ for ( i = 0; i < 3; i++ )
+ {
+ newOrigin[i] += ( VEC_PRONE_HULL_MIN_SCALED( player )[i] - vecMins[i] );
+ }
+ }
+ else
+ {
+ // If in air an letting go of crouch, make sure we can offset origin to make
+ // up for uncrouching
+
+ Vector hullSizeNormal = vecMaxs - vecMins;
+ Vector hullSizeProne = VEC_PRONE_HULL_MAX_SCALED( player ) - VEC_PRONE_HULL_MIN_SCALED( player );
+
+ Vector viewDelta = -0.5f * ( hullSizeNormal - hullSizeProne );
+
+ VectorAdd( newOrigin, viewDelta, newOrigin );
+ }
+
+ bool saveprone = m_pDODPlayer->m_Shared.IsProne();
+ bool saveducked = player->m_Local.m_bDucked;
+
+ // pretend we're not prone
+ m_pDODPlayer->m_Shared.SetProne( false );
+ if ( mv->m_nButtons & IN_DUCK )
+ player->m_Local.m_bDucked = true;
+
+ TracePlayerBBox( mv->GetAbsOrigin(), newOrigin, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace );
+
+ // revert to reality
+ m_pDODPlayer->m_Shared.SetProne( saveprone );
+ player->m_Local.m_bDucked = saveducked;
+
+ if ( trace.startsolid || ( trace.fraction != 1.0f ) )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Stop ducking
+//-----------------------------------------------------------------------------
+void CDODGameMovement::FinishUnDuck( void )
+{
+ int i;
+ trace_t trace;
+ Vector newOrigin;
+
+ VectorCopy( mv->GetAbsOrigin(), newOrigin );
+
+ if ( player->GetGroundEntity() != NULL )
+ {
+ for ( i = 0; i < 3; i++ )
+ {
+ newOrigin[i] += ( VEC_DUCK_HULL_MIN_SCALED( player )[i] - VEC_HULL_MIN_SCALED( player )[i] );
+ }
+ }
+ else
+ {
+ // If in air an letting go of crouch, make sure we can offset origin to make
+ // up for uncrouching
+ // orange box patch - made this match the check in CanUnduck()
+ Vector hullSizeNormal = VEC_HULL_MAX_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
+ Vector hullSizeCrouch = VEC_DUCK_HULL_MAX_SCALED( player ) - VEC_DUCK_HULL_MIN_SCALED( player );
+ Vector viewDelta = ( hullSizeNormal - hullSizeCrouch );
+ viewDelta.Negate();
+ VectorAdd( newOrigin, viewDelta, newOrigin );
+ }
+
+ player->m_Local.m_bDucked = false;
+ player->RemoveFlag( FL_DUCKING );
+ player->m_Local.m_bDucking = false;
+ SetViewOffset( GetPlayerViewOffset( false ) );
+ player->m_Local.m_flDucktime = 0;
+
+ mv->SetAbsOrigin( newOrigin );
+
+ // Recategorize position since ducking can change origin
+ CategorizePosition();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Finish ducking
+//-----------------------------------------------------------------------------
+void CDODGameMovement::FinishDuck( void )
+{
+ Vector hullSizeNormal = VEC_HULL_MAX_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
+ Vector hullSizeCrouch = VEC_DUCK_HULL_MAX_SCALED( player ) - VEC_DUCK_HULL_MIN_SCALED( player );
+
+ Vector viewDelta = 0.5f * ( hullSizeNormal - hullSizeCrouch );
+
+ SetViewOffset( GetPlayerViewOffset( true ) );
+ player->AddFlag( FL_DUCKING );
+ player->m_Local.m_bDucking = false;
+
+ if ( !player->m_Local.m_bDucked )
+ {
+ Vector org = mv->GetAbsOrigin();
+
+ if ( player->GetGroundEntity() != NULL )
+ {
+ org -= VEC_DUCK_HULL_MIN_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
+ }
+ else
+ {
+ VectorAdd( org, viewDelta, org );
+ }
+ mv->SetAbsOrigin( org );
+
+ player->m_Local.m_bDucked = true;
+ }
+
+ // See if we are stuck?
+ FixPlayerCrouchStuck( true );
+
+ // Recategorize position since ducking can change origin
+ CategorizePosition();
+}
+
+// Being deployed or undeploying totally stomps the duck view offset
+void CDODGameMovement::SetDeployedEyeOffset( void )
+{
+ if ( m_pDODPlayer->m_Shared.IsProne() || m_pDODPlayer->m_Shared.IsGettingUpFromProne() )
+ return;
+
+ if ( !m_pDODPlayer->IsAlive() )
+ return;
+
+ float flTimeSinceDeployChange = gpGlobals->curtime - m_pDODPlayer->m_Shared.m_flDeployChangeTime;
+
+ if ( m_pDODPlayer->m_Shared.IsInMGDeploy() || flTimeSinceDeployChange < TIME_TO_DEPLOY )
+ {
+ if ( m_pDODPlayer->m_Shared.IsInMGDeploy() )
+ {
+ // anim to deployed
+ if ( m_pDODPlayer->m_Shared.GetLastViewAnimTime() < m_pDODPlayer->m_Shared.m_flDeployChangeTime.m_Value )
+ {
+ // Deployed height
+ float flViewOffset = clamp( m_pDODPlayer->m_Shared.GetDeployedHeight(),
+ CROUCHING_DEPLOY_HEIGHT,
+ STANDING_DEPLOY_HEIGHT );
+
+ Vector vecView = player->GetViewOffset();
+ vecView.z = flViewOffset;
+
+ ViewOffsetAnimation( vecView, TIME_TO_DEPLOY, VIEW_ANIM_LINEAR_Z_ONLY );
+ m_pDODPlayer->m_Shared.SetLastViewAnimTime( gpGlobals->curtime );
+ }
+ }
+ else
+ {
+ // anim to undeployed
+ if ( m_pDODPlayer->m_Shared.GetLastViewAnimTime() < m_pDODPlayer->m_Shared.m_flDeployChangeTime.m_Value )
+ {
+ ViewOffsetAnimation( GetPlayerViewOffset( player->m_Local.m_bDucked ), TIME_TO_DEPLOY, VIEW_ANIM_LINEAR_Z_ONLY );
+ m_pDODPlayer->m_Shared.SetLastViewAnimTime( gpGlobals->curtime );
+ }
+ }
+
+ if ( flTimeSinceDeployChange >= TIME_TO_DEPLOY )
+ {
+ player->m_Local.m_bDucked = false;
+ player->RemoveFlag( FL_DUCKING );
+ player->m_Local.m_bDucking = false;
+ player->m_Local.m_flDucktime = 0;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : duckFraction -
+//-----------------------------------------------------------------------------
+void CDODGameMovement::SetDODDuckedEyeOffset( float duckFraction )
+{
+ // Different from CGameMovement in that
+ Vector vDuckHullMin = GetPlayerMins( true );
+ Vector vStandHullMin = GetPlayerMins( false );
+
+ float fMore = ( vDuckHullMin.z - vStandHullMin.z );
+
+ Vector vecStandViewOffset = GetPlayerViewOffset( false );
+
+ Vector vecDuckViewOffset = GetPlayerViewOffset( true );
+ Vector temp = player->GetViewOffset();
+ temp.z = ( ( vecDuckViewOffset.z - fMore ) * duckFraction ) +
+ ( vecStandViewOffset.z * ( 1 - duckFraction ) );
+ SetViewOffset( temp );
+}
+
+void CDODGameMovement::SetProneEyeOffset( float proneFraction )
+{
+ Vector vecPropViewOffset = VEC_PRONE_VIEW;
+ Vector vecStandViewOffset = GetPlayerViewOffset( player->m_Local.m_bDucked );
+
+ Vector temp = player->GetViewOffset();
+ temp.z = SimpleSplineRemapVal( proneFraction, 1.0, 0.0, vecPropViewOffset.z, vecStandViewOffset.z );
+
+ SetViewOffset( temp );
+}
+
+void CDODGameMovement::FinishUnProne( void )
+{
+ m_pDODPlayer->m_Shared.m_flUnProneTime = 0.0f;
+
+ SetProneEyeOffset( 0.0 );
+
+ Vector vHullMin = GetPlayerMins( player->m_Local.m_bDucked );
+ Vector vHullMax = GetPlayerMaxs( player->m_Local.m_bDucked );
+
+ if ( m_bUnProneToDuck )
+ {
+ FinishDuck();
+ }
+ else
+ {
+ CategorizePosition();
+
+ if ( mv->m_nButtons & IN_DUCK && !( player->GetFlags() & FL_DUCKING ) )
+ {
+ // Use 1 second so super long jump will work
+ player->m_Local.m_flDucktime = 1000;
+ player->m_Local.m_bDucking = true;
+ }
+ }
+}
+
+void CDODGameMovement::FinishProne( void )
+{
+ m_pDODPlayer->m_Shared.SetProne( true );
+ m_pDODPlayer->m_Shared.m_flGoProneTime = 0.0f;
+
+#ifndef CLIENT_DLL
+ m_pDODPlayer->HintMessage( HINT_PRONE );
+#endif
+
+ FinishUnDuck(); // clear ducking
+
+ SetProneEyeOffset( 1.0 );
+
+ FixPlayerCrouchStuck(true);
+
+ CategorizePosition();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: See if duck button is pressed and do the appropriate things
+//-----------------------------------------------------------------------------
+void CDODGameMovement::Duck( void )
+{
+ int buttonsChanged = ( mv->m_nOldButtons ^ mv->m_nButtons ); // These buttons have changed this frame
+ int buttonsPressed = buttonsChanged & mv->m_nButtons; // The changed ones still down are "pressed"
+ int buttonsReleased = buttonsChanged & mv->m_nOldButtons; // The changed ones which were previously down are "released"
+
+ if ( mv->m_nButtons & IN_DUCK )
+ {
+ mv->m_nOldButtons |= IN_DUCK;
+ }
+ else
+ {
+ mv->m_nOldButtons &= ~IN_DUCK;
+ }
+
+ if ( !player->IsAlive() )
+ {
+ if( m_pDODPlayer->m_Shared.IsProne() )
+ {
+ FinishUnProne();
+ }
+
+ // Unduck
+ if ( player->m_Local.m_bDucking || player->m_Local.m_bDucked )
+ {
+ FinishUnDuck();
+ }
+ return;
+ }
+
+ static int iState = 0;
+
+ // Prone / UnProne - we don't duck or deploy if this is happening
+ if( m_pDODPlayer->m_Shared.m_flUnProneTime > 0.0f )
+ {
+ float pronetime = m_pDODPlayer->m_Shared.m_flUnProneTime - gpGlobals->curtime;
+
+ if( pronetime < 0 )
+ {
+ FinishUnProne();
+
+ if ( !m_bUnProneToDuck && ( mv->m_nButtons & IN_DUCK ) )
+ {
+ buttonsPressed |= IN_DUCK;
+ mv->m_nOldButtons &= ~IN_DUCK;
+ }
+ }
+
+ // Set these, so that as soon as we stop unproning, we don't pop to standing
+ // the information that we let go of the duck key has been lost by now.
+ if ( m_bUnProneToDuck )
+ {
+ player->m_Local.m_flDucktime = 1000;
+ player->m_Local.m_bDucking = true;
+ }
+
+ //don't deal with ducking while we're proning
+ return;
+ }
+ else if( m_pDODPlayer->m_Shared.m_flGoProneTime > 0.0f )
+ {
+ float pronetime = m_pDODPlayer->m_Shared.m_flGoProneTime - gpGlobals->curtime;
+
+ if( pronetime < 0 )
+ {
+ FinishProne();
+ }
+
+ //don't deal with ducking while we're proning
+ return;
+ }
+
+ if ( gpGlobals->curtime > m_pDODPlayer->m_Shared.m_flNextProneCheck )
+ {
+ if ( buttonsPressed & IN_ALT1 && m_pDODPlayer->m_Shared.CanChangePosition() )
+ {
+ if( m_pDODPlayer->m_Shared.IsProne() == false &&
+ m_pDODPlayer->m_Shared.IsGettingUpFromProne() == false )
+ {
+ m_pDODPlayer->m_Shared.StartGoingProne();
+
+ // do unprone anim
+ ViewOffsetAnimation( VEC_PRONE_VIEW, TIME_TO_PRONE, VIEW_ANIM_EXPONENTIAL_Z_ONLY );
+ }
+ else if( CanUnprone() )
+ {
+ m_pDODPlayer->m_Shared.SetProne( false );
+ m_pDODPlayer->m_Shared.StandUpFromProne();
+
+ // do unprone anim
+ ViewOffsetAnimation( GetPlayerViewOffset( m_bUnProneToDuck ),
+ TIME_TO_PRONE,
+ VIEW_ANIM_EXPONENTIAL_Z_ONLY );
+
+ m_bUnProneToDuck = ( mv->m_nButtons & IN_DUCK ) > 0;
+ }
+
+ m_pDODPlayer->m_Shared.m_flNextProneCheck = gpGlobals->curtime + 1.0f;
+ return;
+ }
+ }
+
+ SetDeployedEyeOffset();
+
+ if ( m_pDODPlayer->m_Shared.IsProne() &&
+ m_pDODPlayer->m_Shared.CanChangePosition() &&
+ !m_pDODPlayer->m_Shared.IsGettingUpFromProne() &&
+ ( buttonsPressed & IN_DUCK ) &&
+ CanUnprone() ) // BUGBUG - even calling this will unzoom snipers.
+ {
+ // If the player presses duck while prone,
+ // unprone them to the duck position
+ m_pDODPlayer->m_Shared.SetProne( false );
+ m_pDODPlayer->m_Shared.StandUpFromProne();
+
+ m_bUnProneToDuck = true;
+
+ // do unprone anim
+ ViewOffsetAnimation( GetPlayerViewOffset( m_bUnProneToDuck ),
+ TIME_TO_PRONE,
+ VIEW_ANIM_EXPONENTIAL_Z_ONLY );
+
+ // simulate a duck that was pressed while we were prone
+ player->AddFlag( FL_DUCKING );
+ player->m_Local.m_bDucked = true;
+ player->m_Local.m_flDucktime = 1000;
+ player->m_Local.m_bDucking = true;
+ }
+
+ // no ducking or unducking while deployed or prone
+ if( m_pDODPlayer->m_Shared.IsProne() ||
+ m_pDODPlayer->m_Shared.IsGettingUpFromProne() ||
+ !m_pDODPlayer->m_Shared.CanChangePosition() )
+ {
+ return;
+ }
+
+ HandleDuckingSpeedCrop();
+
+ if ( !( player->GetFlags() & FL_DUCKING ) && ( player->m_Local.m_bDucked ) )
+ {
+ player->m_Local.m_bDucked = false;
+ }
+
+ /*
+ Msg( "duck button %s ducking %s ducked %s duck flags %s\n",
+ ( mv->m_nButtons & IN_DUCK ) ? "down" : "up",
+ ( player->m_Local.m_bDucking ) ? "yes" : "no",
+ ( player->m_Local.m_bDucked ) ? "yes" : "no",
+ ( player->GetFlags() & FL_DUCKING ) ? "set" : "not set" );*/
+
+ // Holding duck, in process of ducking or fully ducked?
+ if ( ( mv->m_nButtons & IN_DUCK ) || ( player->m_Local.m_bDucking ) || ( player->GetFlags() & FL_DUCKING ) )
+ {
+ if ( mv->m_nButtons & IN_DUCK )
+ {
+ bool alreadyDucked = ( player->GetFlags() & FL_DUCKING ) ? true : false;
+
+ if ( (buttonsPressed & IN_DUCK ) && !( player->GetFlags() & FL_DUCKING ) )
+ {
+ // Use 1 second so super long jump will work
+ player->m_Local.m_flDucktime = 1000;
+ player->m_Local.m_bDucking = true;
+ }
+
+ float duckmilliseconds = MAX( 0.0f, 1000.0f - (float)player->m_Local.m_flDucktime );
+ float duckseconds = duckmilliseconds / 1000.0f;
+
+ //time = MAX( 0.0, ( 1.0 - (float)player->m_Local.m_flDucktime / 1000.0 ) );
+
+ if ( player->m_Local.m_bDucking )
+ {
+ // Finish ducking immediately if duck time is over or not on ground
+ if ( ( duckseconds > TIME_TO_DUCK ) ||
+ ( player->GetGroundEntity() == NULL ) ||
+ alreadyDucked)
+ {
+ FinishDuck();
+ }
+ else
+ {
+ // Calc parametric time
+ float flDuckFraction = SimpleSpline( duckseconds / TIME_TO_DUCK );
+ SetDODDuckedEyeOffset( flDuckFraction );
+ }
+ }
+ }
+ else
+ {
+ // Try to unduck unless automovement is not allowed
+ // NOTE: When not onground, you can always unduck
+ if ( player->m_Local.m_bAllowAutoMovement || player->GetGroundEntity() == NULL )
+ {
+ if ( (buttonsReleased & IN_DUCK ) && ( player->GetFlags() & FL_DUCKING ) )
+ {
+ // Use 1 second so super long jump will work
+ player->m_Local.m_flDucktime = 1000;
+ player->m_Local.m_bDucking = true; // or unducking
+ }
+
+ float duckmilliseconds = MAX( 0.0f, 1000.0f - (float)player->m_Local.m_flDucktime );
+ float duckseconds = duckmilliseconds / 1000.0f;
+
+ if ( CanUnduck() )
+ {
+ if ( player->m_Local.m_bDucking ||
+ player->m_Local.m_bDucked ) // or unducking
+ {
+ // Finish ducking immediately if duck time is over or not on ground
+ if ( ( duckseconds > TIME_TO_UNDUCK ) ||
+ ( player->GetGroundEntity() == NULL ) )
+ {
+ FinishUnDuck();
+ }
+ else
+ {
+ // Calc parametric time
+ float duckFraction = SimpleSpline( 1.0f - ( duckseconds / TIME_TO_UNDUCK ) );
+ SetDODDuckedEyeOffset( duckFraction );
+ }
+ }
+ }
+ else
+ {
+ // Still under something where we can't unduck, so make sure we reset this timer so
+ // that we'll unduck once we exit the tunnel, etc.
+ player->m_Local.m_flDucktime = 1000;
+ }
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input :
+// Output : const Vector
+//-----------------------------------------------------------------------------
+Vector CDODGameMovement::GetPlayerMins( void ) const
+{
+ if ( !player )
+ {
+ return vec3_origin;
+ }
+
+ if ( player->IsObserver() )
+ {
+ return VEC_OBS_HULL_MIN_SCALED( player );
+ }
+ else
+ {
+ if ( player->m_Local.m_bDucked )
+ return VEC_DUCK_HULL_MIN_SCALED( player );
+ else if ( m_pDODPlayer->m_Shared.IsProne() )
+ return VEC_PRONE_HULL_MIN_SCALED( player );
+ else
+ return VEC_HULL_MIN_SCALED( player );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input :
+// Output : const Vector
+//-----------------------------------------------------------------------------
+Vector CDODGameMovement::GetPlayerMaxs( void ) const
+{
+ if ( !player )
+ {
+ return vec3_origin;
+ }
+ if ( player->IsObserver() )
+ {
+ return VEC_OBS_HULL_MAX_SCALED( player );
+ }
+ else
+ {
+ if ( player->m_Local.m_bDucked )
+ return VEC_DUCK_HULL_MAX_SCALED( player );
+ else if ( m_pDODPlayer->m_Shared.IsProne() )
+ return VEC_PRONE_HULL_MAX_SCALED( player );
+ else
+ return VEC_HULL_MAX_SCALED( player );
+ }
+}
+
+void CDODGameMovement::SetViewOffset( Vector vecViewOffset )
+{
+ // call this instead of player->SetViewOffset directly, so we can cancel any
+ // animation in progress
+
+ m_pDODPlayer->m_Shared.ResetViewOffsetAnimation();
+
+ player->SetViewOffset( vecViewOffset );
+}
+
+void CDODGameMovement::ViewOffsetAnimation( Vector vecDest, float flTime, ViewAnimationType type )
+{
+ m_pDODPlayer->m_Shared.ViewOffsetAnimation( vecDest, flTime, type );
+} \ No newline at end of file
diff --git a/game/shared/dod/dod_gamerules.cpp b/game/shared/dod/dod_gamerules.cpp
new file mode 100644
index 0000000..9a9e48d
--- /dev/null
+++ b/game/shared/dod/dod_gamerules.cpp
@@ -0,0 +1,5595 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: The TF Game rules
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "dod_gamerules.h"
+#include "ammodef.h"
+#include "KeyValues.h"
+#include "weapon_dodbase.h"
+#include "filesystem.h" // for WriteStatsFile
+
+
+#ifdef CLIENT_DLL
+
+ #include "precache_register.h"
+ #include "c_dod_player.h"
+
+#else
+
+ #include "coordsize.h"
+ #include "dod_player.h"
+ #include "voice_gamemgr.h"
+ #include "team.h"
+ #include "dod_player.h"
+ #include "dod_bot_temp.h"
+ #include "game.h"
+ #include "dod_shareddefs.h"
+ #include "player_resource.h"
+ #include "mapentities.h"
+ #include "dod_gameinterface.h"
+ #include "dod_objective_resource.h"
+ #include "dod_cvars.h"
+ #include "dod_team.h"
+ #include "dod_playerclass_info_parse.h"
+ #include "dod_control_point_master.h"
+ #include "dod_bombtarget.h"
+ //#include "teamplayroundbased_gamerules.h"
+ #include "weapon_dodbipodgun.h"
+
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#ifndef CLIENT_DLL
+
+BEGIN_DATADESC(CSpawnPoint)
+
+ // Keyfields
+ DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ),
+
+ // Inputs
+ DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
+
+END_DATADESC();
+
+LINK_ENTITY_TO_CLASS(info_player_allies, CSpawnPoint);
+LINK_ENTITY_TO_CLASS(info_player_axis, CSpawnPoint);
+
+#endif
+
+REGISTER_GAMERULES_CLASS( CDODGameRules );
+
+#define MAX_RESPAWN_WAVES_TO_TRANSMIT 5
+
+#ifdef CLIENT_DLL
+void RecvProxy_RoundState( const CRecvProxyData *pData, void *pStruct, void *pOut )
+{
+ CDODGameRules *pGamerules = ( CDODGameRules *)pStruct;
+
+ int iRoundState = pData->m_Value.m_Int;
+
+ pGamerules->SetRoundState( iRoundState );
+}
+#endif
+
+BEGIN_NETWORK_TABLE_NOBASE( CDODGameRules, DT_DODGameRules )
+ #ifdef CLIENT_DLL
+
+ RecvPropInt( RECVINFO( m_iRoundState ), 0, RecvProxy_RoundState ),
+ RecvPropBool( RECVINFO( m_bInWarmup ) ),
+ RecvPropBool( RECVINFO( m_bAwaitingReadyRestart ) ),
+ RecvPropTime( RECVINFO( m_flMapResetTime ) ),
+ RecvPropTime( RECVINFO( m_flRestartRoundTime ) ),
+ RecvPropBool( RECVINFO( m_bAlliesAreBombing ) ),
+ RecvPropBool( RECVINFO( m_bAxisAreBombing ) ),
+
+ RecvPropArray3( RECVINFO_ARRAY(m_AlliesRespawnQueue), RecvPropTime( RECVINFO(m_AlliesRespawnQueue[0]) ) ),
+ RecvPropArray3( RECVINFO_ARRAY(m_AxisRespawnQueue), RecvPropTime( RECVINFO(m_AxisRespawnQueue[0]) ) ),
+ RecvPropInt( RECVINFO( m_iAlliesRespawnHead ) ),
+ RecvPropInt( RECVINFO( m_iAlliesRespawnTail ) ),
+ RecvPropInt( RECVINFO( m_iAxisRespawnHead ) ),
+ RecvPropInt( RECVINFO( m_iAxisRespawnTail ) ),
+
+ #else
+
+ SendPropInt( SENDINFO( m_iRoundState ), 5 ),
+ SendPropBool( SENDINFO( m_bInWarmup ) ),
+ SendPropBool( SENDINFO( m_bAwaitingReadyRestart ) ),
+ SendPropTime( SENDINFO( m_flMapResetTime ) ),
+ SendPropTime( SENDINFO( m_flRestartRoundTime ) ),
+ SendPropBool( SENDINFO( m_bAlliesAreBombing ) ),
+ SendPropBool( SENDINFO( m_bAxisAreBombing ) ),
+
+ SendPropArray3( SENDINFO_ARRAY3(m_AlliesRespawnQueue), SendPropTime( SENDINFO_ARRAY(m_AlliesRespawnQueue) ) ),
+ SendPropArray3( SENDINFO_ARRAY3(m_AxisRespawnQueue), SendPropTime( SENDINFO_ARRAY(m_AxisRespawnQueue) ) ),
+ SendPropInt( SENDINFO( m_iAlliesRespawnHead ), Q_log2( DOD_RESPAWN_QUEUE_SIZE ) + 1, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO( m_iAlliesRespawnTail ), Q_log2( DOD_RESPAWN_QUEUE_SIZE ) + 1, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO( m_iAxisRespawnHead ), Q_log2( DOD_RESPAWN_QUEUE_SIZE ) + 1, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO( m_iAxisRespawnTail ), Q_log2( DOD_RESPAWN_QUEUE_SIZE ) + 1, SPROP_UNSIGNED ),
+
+ #endif
+END_NETWORK_TABLE()
+
+#ifndef CLIENT_DLL
+ConVar dod_flagrespawnbonus( "dod_flagrespawnbonus", "1.0", FCVAR_GAMEDLL | FCVAR_CHEAT, "How many seconds per advantage flag to decrease the respawn time" );
+
+ConVar mp_warmup_time( "mp_warmup_time", "0", FCVAR_GAMEDLL, "Warmup time length in seconds" );
+ConVar mp_restartwarmup( "mp_restartwarmup", "0", FCVAR_GAMEDLL, "Set to 1 to start or restart the warmup period." );
+ConVar mp_cancelwarmup( "mp_cancelwarmup", "0", FCVAR_GAMEDLL, "Set to 1 to end the warmup period." );
+#endif
+
+ConVar dod_enableroundwaittime( "dod_enableroundwaittime", "1", FCVAR_REPLICATED, "Enable timers to wait between rounds." );
+ConVar mp_allowrandomclass( "mp_allowrandomclass", "1", FCVAR_REPLICATED, "Allow players to select random class" );
+
+ConVar dod_bonusroundtime( "dod_bonusroundtime", "15", FCVAR_REPLICATED, "Time after round win until round restarts", true, 5, true, 15 );
+
+LINK_ENTITY_TO_CLASS( dod_gamerules, CDODGameRulesProxy );
+IMPLEMENT_NETWORKCLASS_ALIASED( DODGameRulesProxy, DT_DODGameRulesProxy )
+
+
+#ifdef CLIENT_DLL
+ void RecvProxy_DODGameRules( const RecvProp *pProp, void **pOut, void *pData, int objectID )
+ {
+ CDODGameRules *pRules = DODGameRules();
+ Assert( pRules );
+ *pOut = pRules;
+ }
+
+ BEGIN_RECV_TABLE( CDODGameRulesProxy, DT_DODGameRulesProxy )
+ RecvPropDataTable( "dod_gamerules_data", 0, 0, &REFERENCE_RECV_TABLE( DT_DODGameRules ), RecvProxy_DODGameRules )
+ END_RECV_TABLE()
+#else
+ void* SendProxy_DODGameRules( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID )
+ {
+ CDODGameRules *pRules = DODGameRules();
+ Assert( pRules );
+ pRecipients->SetAllRecipients();
+ return pRules;
+ }
+
+ BEGIN_SEND_TABLE( CDODGameRulesProxy, DT_DODGameRulesProxy )
+ SendPropDataTable( "dod_gamerules_data", 0, &REFERENCE_SEND_TABLE( DT_DODGameRules ), SendProxy_DODGameRules )
+ END_SEND_TABLE()
+#endif
+
+static CDODViewVectors g_DODViewVectors(
+
+ Vector( 0, 0, 58 ), //VEC_VIEW (m_vView)
+
+ Vector(-16, -16, 0 ), //VEC_HULL_MIN (m_vHullMin)
+ Vector( 16, 16, 72 ), //VEC_HULL_MAX (m_vHullMax)
+
+ Vector(-16, -16, 0 ), //VEC_DUCK_HULL_MIN (m_vDuckHullMin)
+ Vector( 16, 16, 45 ), //VEC_DUCK_HULL_MAX (m_vDuckHullMax)
+ Vector( 0, 0, 34 ), //VEC_DUCK_VIEW (m_vDuckView)
+
+ Vector(-10, -10, -10 ), //VEC_OBS_HULL_MIN (m_vObsHullMin)
+ Vector( 10, 10, 10 ), //VEC_OBS_HULL_MAX (m_vObsHullMax)
+
+ Vector( 0, 0, 14 ), //VEC_DEAD_VIEWHEIGHT (m_vDeadViewHeight)
+
+ Vector(-16, -16, 0 ), //VEC_PRONE_HULL_MIN (m_vProneHullMin)
+ Vector( 16, 16, 24 ) //VEC_PRONE_HULL_MAX (m_vProneHullMax)
+);
+
+
+#ifdef CLIENT_DLL
+
+
+#else
+
+ void ParseEntKVBlock( CBaseEntity *pNode, KeyValues *pkvNode )
+ {
+ KeyValues *pkvNodeData = pkvNode->GetFirstSubKey();
+ while ( pkvNodeData )
+ {
+ // Handle the connections block
+ if ( !Q_strcmp(pkvNodeData->GetName(), "connections") )
+ {
+ ParseEntKVBlock( pNode, pkvNodeData );
+ }
+ else
+ {
+ pNode->KeyValue( pkvNodeData->GetName(), pkvNodeData->GetString() );
+ }
+
+ pkvNodeData = pkvNodeData->GetNextKey();
+ }
+ }
+
+ CUtlVector<EHANDLE> m_hSpawnedEntities;
+
+ // for now only allow blocker walls to load this way
+ bool CanLoadEntityFromEntText( const char *clsName )
+ {
+ if ( !Q_strcmp( clsName, "func_team_wall" ) )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ void Load_EntText( void )
+ {
+ bool oldLock = engine->LockNetworkStringTables( false );
+
+ // remove all ents in m_SpawnedEntities
+ for ( int i = 0; i < m_hSpawnedEntities.Count(); i++ )
+ {
+ UTIL_Remove( m_hSpawnedEntities[i] );
+ }
+
+ // delete the items from our list
+ m_hSpawnedEntities.RemoveAll();
+
+ // Find the commentary file
+ char szFullName[512];
+ Q_snprintf(szFullName,sizeof(szFullName), "maps/%s.ent", STRING( gpGlobals->mapname ));
+ KeyValues *pkvFile = new KeyValues( "EntText" );
+ if ( pkvFile->LoadFromFile( filesystem, szFullName, "MOD" ) )
+ {
+ DevMsg( "Load_EntText: Loading entity data from %s. \n", szFullName );
+
+ // Load each commentary block, and spawn the entities
+ KeyValues *pkvNode = pkvFile->GetFirstSubKey();
+ while ( pkvNode )
+ {
+ // Get node name
+ const char *pNodeName = pkvNode->GetName();
+ KeyValues *pClassname = pkvNode->FindKey( "classname" );
+ if ( pClassname )
+ {
+ // Use the classname instead
+ pNodeName = pClassname->GetString();
+ }
+
+ if ( CanLoadEntityFromEntText( pNodeName ) )
+ {
+ // Spawn the entity
+ CBaseEntity *pNode = CreateEntityByName( pNodeName );
+ if ( pNode )
+ {
+ ParseEntKVBlock( pNode, pkvNode );
+ DispatchSpawn( pNode );
+
+ EHANDLE hHandle;
+ hHandle = pNode;
+ m_hSpawnedEntities.AddToTail( hHandle );
+ }
+ else
+ {
+ Warning("Load_EntText: Failed to spawn entity, type: '%s'\n", pNodeName );
+ }
+ }
+
+ // Move to next entity
+ pkvNode = pkvNode->GetNextKey();
+ }
+
+ // Then activate all the entities
+ for ( int i = 0; i < m_hSpawnedEntities.Count(); i++ )
+ {
+ m_hSpawnedEntities[i]->Activate();
+ }
+ }
+ else
+ {
+ DevMsg( "Load_EntText: Could not find entity data file '%s'. \n", szFullName );
+ }
+
+ engine->LockNetworkStringTables( oldLock );
+ }
+
+ // --------------------------------------------------------------------------------------------------- //
+ // Voice helper
+ // --------------------------------------------------------------------------------------------------- //
+
+ class CVoiceGameMgrHelper : public IVoiceGameMgrHelper
+ {
+ public:
+ virtual bool CanPlayerHearPlayer( CBasePlayer *pListener, CBasePlayer *pTalker, bool &bProximity )
+ {
+ // Dead players can only be heard by other dead team mates
+ if ( pTalker->IsAlive() == false )
+ {
+ if ( pListener->IsAlive() == false )
+ return ( pListener->InSameTeam( pTalker ) );
+
+ return false;
+ }
+
+ return ( pListener->InSameTeam( pTalker ) );
+ }
+ };
+ CVoiceGameMgrHelper g_VoiceGameMgrHelper;
+ IVoiceGameMgrHelper *g_pVoiceGameMgrHelper = &g_VoiceGameMgrHelper;
+
+
+
+ // --------------------------------------------------------------------------------------------------- //
+ // Globals.
+ // --------------------------------------------------------------------------------------------------- //
+
+ // NOTE: the indices here must match TEAM_TERRORIST, TEAM_ALLIES, TEAM_AXIS, etc.
+ char *sTeamNames[] =
+ {
+ "Unassigned",
+ "Spectator",
+ "Allies",
+ "Axis"
+ };
+
+ static const char *s_PreserveEnts[] =
+ {
+ "player",
+ "viewmodel",
+ "worldspawn",
+ "soundent",
+ "ai_network",
+ "ai_hint",
+ "dod_gamerules",
+ "dod_team_manager",
+ "dod_player_manager",
+ "dod_objective_resource",
+ "env_soundscape",
+ "env_soundscape_proxy",
+ "env_soundscape_triggerable",
+ "env_sprite",
+ "env_sun",
+ "env_wind",
+ "env_fog_controller",
+ "func_brush",
+ "func_wall",
+ "func_illusionary",
+ "info_node",
+ "info_target",
+ "info_node_hint",
+ "info_player_allies",
+ "info_player_axis",
+ "point_viewcontrol",
+ "shadow_control",
+ "sky_camera",
+ "scene_manager",
+ "trigger_soundscape",
+ "info_dod_detect",
+ "dod_team_allies",
+ "dod_team_axis",
+ "point_commentary_node",
+ "dod_round_timer",
+ "func_precipitation",
+ "func_team_wall",
+ "", // END Marker
+ };
+
+ // --------------------------------------------------------------------------------------------------- //
+ // Global helper functions.
+ // --------------------------------------------------------------------------------------------------- //
+
+ // World.cpp calls this but we don't use it in DoD.
+ void InitBodyQue()
+ {
+ }
+
+
+ // Handler for the "bot" command.
+ CON_COMMAND_F( bot, "Add a bot.", FCVAR_CHEAT )
+ {
+ //CDODPlayer *pPlayer = CDODPlayer::Instance( UTIL_GetCommandClientIndex() );
+
+ // The bot command uses switches like command-line switches.
+ // -count <count> tells how many bots to spawn.
+ // -team <index> selects the bot's team. Default is -1 which chooses randomly.
+ // Note: if you do -team !, then it
+ // -class <index> selects the bot's class. Default is -1 which chooses randomly.
+ // -frozen prevents the bots from running around when they spawn in.
+
+ // Look at -count.
+ int count = args.FindArgInt( "-count", 1 );
+ count = clamp( count, 1, 16 );
+
+ int iTeam = TEAM_ALLIES;
+ const char *pVal = args.FindArg( "-team" );
+ if ( pVal )
+ {
+ iTeam = atoi( pVal );
+ iTeam = clamp( iTeam, 0, (GetNumberOfTeams()-1) );
+ }
+
+ int iClass = 0;
+ pVal = args.FindArg( "-class" );
+ if ( pVal )
+ {
+ iClass = atoi( pVal );
+ iClass = clamp( iClass, 0, 10 );
+ }
+
+ // Look at -frozen.
+ bool bFrozen = !!args.FindArg( "-frozen" );
+
+ // Ok, spawn all the bots.
+ while ( --count >= 0 )
+ {
+ BotPutInServer( bFrozen, iTeam, iClass );
+ }
+ }
+
+
+ void RestartRound_f()
+ {
+ DODGameRules()->State_Transition( STATE_RESTART );
+ }
+ ConCommand cc_Restart( "restartround", RestartRound_f, "Restart the round", FCVAR_CHEAT );
+
+ void CDODGameRules::CopyGamePlayLogic( const CDODGamePlayRules otherGamePlay )
+ {
+ m_GamePlayRules.CopyFrom( otherGamePlay );
+ }
+
+ // --------------------------------------------------------------------------------------------------- //
+ // CDODGameRules implementation.
+ // --------------------------------------------------------------------------------------------------- //
+
+ CDODGameRules::CDODGameRules()
+ {
+ InitTeams();
+
+ ResetMapTime();
+
+ m_GamePlayRules.Reset();
+
+ ResetScores();
+
+ m_bInWarmup = false;
+ m_bAwaitingReadyRestart = false;
+ m_flRestartRoundTime = -1;
+
+ m_iAlliesRespawnHead = 0;
+ m_iAlliesRespawnTail = 0;
+ m_iAxisRespawnHead = 0;
+ m_iAxisRespawnTail = 0;
+ m_iNumAlliesRespawnWaves = 0;
+ m_iNumAxisRespawnWaves = 0;
+
+ for ( int i=0; i <DOD_RESPAWN_QUEUE_SIZE; i++ )
+ {
+ m_AlliesRespawnQueue.Set( i, 0 );
+ m_AxisRespawnQueue.Set( i, 0 );
+ }
+
+ m_bLevelInitialized = false;
+ m_iSpawnPointCount_Allies = 0;
+ m_iSpawnPointCount_Axis = 0;
+
+ Q_memset( m_vecPlayerPositions,0, sizeof(m_vecPlayerPositions) );
+
+ // Lets execute a map specific cfg file
+ // Matt - execute this after server.cfg!
+ char szCommand[256] = { 0 };
+ // Map names cannot contain quotes or control characters so this is safe but silly that we have to do it.
+ Q_snprintf( szCommand, sizeof(szCommand), "exec \"%s.cfg\"\n", STRING(gpGlobals->mapname) );
+ engine->ServerCommand( szCommand );
+
+ m_pCurStateInfo = NULL;
+ State_Transition( STATE_PREGAME );
+
+ // stats
+ memset( m_iStatsKillsPerClass_Allies, 0, sizeof(m_iStatsKillsPerClass_Allies) );
+ memset( m_iStatsKillsPerClass_Axis, 0, sizeof(m_iStatsKillsPerClass_Axis) );
+
+ memset( m_iStatsSpawnsPerClass_Allies, 0, sizeof(m_iStatsSpawnsPerClass_Allies) );
+ memset( m_iStatsSpawnsPerClass_Axis, 0, sizeof(m_iStatsSpawnsPerClass_Axis) );
+
+ memset( m_iStatsCapsPerClass_Allies, 0, sizeof(m_iStatsCapsPerClass_Allies) );
+ memset( m_iStatsCapsPerClass_Axis, 0, sizeof(m_iStatsCapsPerClass_Axis) );
+
+ memset( m_iStatsDefensesPerClass_Allies, 0, sizeof(m_iStatsDefensesPerClass_Allies) );
+ memset( m_iStatsDefensesPerClass_Axis, 0, sizeof(m_iStatsDefensesPerClass_Axis) );
+
+ memset( &m_iWeaponShotsFired, 0, sizeof(m_iWeaponShotsFired) );
+ memset( &m_iWeaponShotsHit, 0, sizeof(m_iWeaponShotsHit) );
+ memset( &m_iWeaponDistanceBuckets, 0, sizeof(m_iWeaponDistanceBuckets) );
+
+ memset( &m_flSecondsPlayedPerClass_Allies, 0, sizeof(m_flSecondsPlayedPerClass_Allies) );
+ memset( &m_flSecondsPlayedPerClass_Axis, 0, sizeof(m_flSecondsPlayedPerClass_Axis) );
+
+ m_bUsingTimer = false;
+ m_pRoundTimer = NULL; // created on first round spawn that requires a timer
+
+ m_bAlliesAreBombing = false;
+ m_bAxisAreBombing = false;
+
+ m_flNextFailSafeWaveCheckTime = 0;
+
+ // Init the holiday
+ int day = 0, month = 0, year = 0;
+
+#ifdef WIN32
+ GetCurrentDate( &day, &month, &year );
+#elif POSIX
+ time_t now = time(NULL);
+ struct tm *tm = localtime( &now );
+
+ day = tm->tm_mday + 1;
+ month = tm->tm_mon;
+ year = tm->tm_year + 1900;
+#endif
+
+ if ( ( month == 12 && day >= 1 ) || ( month == 1 && day <= 2 ) )
+ {
+ m_bWinterHolidayActive = true;
+ }
+ else
+ {
+ m_bWinterHolidayActive = false;
+ }
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ CDODGameRules::~CDODGameRules()
+ {
+ // Note, don't delete each team since they are in the gEntList and will
+ // automatically be deleted from there, instead.
+ g_Teams.Purge();
+ }
+
+ void CDODGameRules::LevelShutdown( void )
+ {
+ UploadLevelStats();
+
+ BaseClass::LevelShutdown();
+ }
+
+ #define MY_USHRT_MAX 0xffff
+ #define MY_UCHAR_MAX 0xff
+
+ void CDODGameRules::UploadLevelStats( void )
+ {
+ if ( Q_strlen( STRING( gpGlobals->mapname ) ) > 0 )
+ {
+ int i,j;
+ CDODTeam *pAllies = GetGlobalDODTeam( TEAM_ALLIES );
+ CDODTeam *pAxis = GetGlobalDODTeam( TEAM_AXIS );
+
+ dod_gamestats_t stats;
+ memset( &stats, 0, sizeof(stats) );
+
+ // Header
+ stats.header.iVersion = DOD_STATS_BLOB_VERSION;
+ Q_strncpy( stats.header.szGameName, "dod", sizeof(stats.header.szGameName) );
+ Q_strncpy( stats.header.szMapName, STRING( gpGlobals->mapname ), sizeof( stats.header.szMapName ) );
+
+ ConVar *hostip = cvar->FindVar( "hostip" );
+ if ( hostip )
+ {
+ int ip = hostip->GetInt();
+ stats.header.ipAddr[0] = ip >> 24;
+ stats.header.ipAddr[1] = ( ip >> 16 ) & 0xff;
+ stats.header.ipAddr[2] = ( ip >> 8 ) & 0xff;
+ stats.header.ipAddr[3] = ( ip ) & 0xff;
+ }
+
+ ConVar *hostport = cvar->FindVar( "hostip" );
+ if ( hostport )
+ {
+ stats.header.port = hostport->GetInt();
+ }
+
+ stats.header.serverid = 0;
+
+ stats.iMinutesPlayed = clamp( (short)( gpGlobals->curtime / 60 ), 0, MY_USHRT_MAX );
+
+ // Team Scores
+ stats.iNumAlliesWins = clamp( pAllies->GetRoundsWon(), 0, MY_UCHAR_MAX );
+ stats.iNumAxisWins = clamp( pAxis->GetRoundsWon(), 0, MY_UCHAR_MAX );
+
+ stats.iAlliesTickPoints = clamp( pAllies->GetScore(), 0, MY_USHRT_MAX );
+ stats.iAxisTickPoints = clamp( pAxis->GetScore(), 0, MY_USHRT_MAX );
+
+ // Player Data
+ for ( i=1;i<=MAX_PLAYERS;i++ )
+ {
+ CDODPlayer *pPlayer = ToDODPlayer( UTIL_PlayerByIndex( i ) );
+
+ if ( pPlayer )
+ {
+ // Sum up the time played for players that are still connected.
+ // players who disconnected had their connect time added in ClientDisconnected
+
+ // Tally the latest time for this player
+ pPlayer->TallyLatestTimePlayedPerClass( pPlayer->GetTeamNumber(), pPlayer->m_Shared.DesiredPlayerClass() );
+
+ for( j=0;j<7;j++ )
+ {
+ m_flSecondsPlayedPerClass_Allies[j] += pPlayer->m_flTimePlayedPerClass_Allies[j];
+ m_flSecondsPlayedPerClass_Axis[j] += pPlayer->m_flTimePlayedPerClass_Axis[j];
+ }
+ }
+ }
+
+ // convert to minutes
+ for( j=0;j<7;j++ )
+ {
+ stats.iMinutesPlayedPerClass_Allies[j] = clamp( (short)( m_flSecondsPlayedPerClass_Allies[j] / 60 ), 0, MY_USHRT_MAX );
+ stats.iMinutesPlayedPerClass_Axis[j] = clamp( (short)( m_flSecondsPlayedPerClass_Axis[j] / 60 ), 0, MY_USHRT_MAX );
+ }
+
+ for ( i=0;i<6;i++ )
+ {
+ stats.iKillsPerClass_Allies[i] = clamp( (short)m_iStatsKillsPerClass_Allies[i], 0, MY_USHRT_MAX );
+ stats.iKillsPerClass_Axis[i] = clamp( (short)m_iStatsKillsPerClass_Axis[i], 0, MY_USHRT_MAX );
+
+ stats.iSpawnsPerClass_Allies[i] = clamp( (short)m_iStatsSpawnsPerClass_Allies[i], 0, MY_USHRT_MAX );
+ stats.iSpawnsPerClass_Axis[i] = clamp( (short)m_iStatsSpawnsPerClass_Axis[i], 0, MY_USHRT_MAX );
+
+ stats.iCapsPerClass_Allies[i] = clamp( (short)m_iStatsCapsPerClass_Allies[i], 0, MY_USHRT_MAX );
+ stats.iCapsPerClass_Axis[i] = clamp( (short)m_iStatsCapsPerClass_Axis[i], 0, MY_USHRT_MAX );
+
+ stats.iDefensesPerClass_Allies[i] = clamp( m_iStatsDefensesPerClass_Allies[i], 0, MY_UCHAR_MAX );
+ stats.iDefensesPerClass_Axis[i] = clamp( m_iStatsDefensesPerClass_Axis[i], 0, MY_UCHAR_MAX );
+ }
+
+ // Server Settings
+ stats.iClassLimits_Allies[0] = clamp( mp_limitAlliesRifleman.GetInt(), -1, 254 );
+ stats.iClassLimits_Allies[1] = clamp( mp_limitAlliesAssault.GetInt(), -1, 254 );
+ stats.iClassLimits_Allies[2] = clamp( mp_limitAlliesSupport.GetInt(), -1, 254 );
+ stats.iClassLimits_Allies[3] = clamp( mp_limitAlliesSniper.GetInt(), -1, 254 );
+ stats.iClassLimits_Allies[4] = clamp( mp_limitAlliesMachinegun.GetInt(), -1, 254 );
+ stats.iClassLimits_Allies[5] = clamp( mp_limitAlliesRocket.GetInt(), -1, 254 );
+
+ stats.iClassLimits_Axis[0] = clamp( mp_limitAxisRifleman.GetInt(), -1, 254 );
+ stats.iClassLimits_Axis[1] = clamp( mp_limitAxisAssault.GetInt(), -1, 254 );
+ stats.iClassLimits_Axis[2] = clamp( mp_limitAxisSupport.GetInt(), -1, 254 );
+ stats.iClassLimits_Axis[3] = clamp( mp_limitAxisSniper.GetInt(), -1, 254 );
+ stats.iClassLimits_Axis[4] = clamp( mp_limitAxisMachinegun.GetInt(), -1, 254 );
+ stats.iClassLimits_Axis[5] = clamp( mp_limitAxisRocket.GetInt(), -1, 254 );
+
+ // Weapon Data
+
+ // Send hit/shots/distance info for the following guns / modes
+ for ( i=0;i<DOD_NUM_DISTANCE_STAT_WEAPONS;i++ )
+ {
+ int weaponId = iDistanceStatWeapons[i];
+
+ stats.weaponStatsDistance[i].iNumHits = clamp( m_iWeaponShotsHit[weaponId], 0, MY_USHRT_MAX );
+ stats.weaponStatsDistance[i].iNumAttacks = clamp( m_iWeaponShotsFired[weaponId], 0, MY_USHRT_MAX );
+ for ( int j=0;j<DOD_NUM_WEAPON_DISTANCE_BUCKETS;j++ )
+ {
+ stats.weaponStatsDistance[i].iDistanceBuckets[j] = clamp( m_iWeaponDistanceBuckets[weaponId][j], 0, MY_USHRT_MAX );
+ }
+ }
+
+ // Send hit/shots info for the following guns / modes
+ for ( i=0;i<DOD_NUM_NODIST_STAT_WEAPONS;i++ )
+ {
+ int weaponId = iNoDistStatWeapons[i];
+ stats.weaponStats[i].iNumHits = clamp( m_iWeaponShotsHit[weaponId], 0, MY_USHRT_MAX );
+ stats.weaponStats[i].iNumAttacks = clamp( m_iWeaponShotsFired[weaponId], 0, MY_USHRT_MAX );
+ }
+
+ const void *pvBlobData = ( const void * )( &stats );
+ unsigned int uBlobSize = sizeof( stats );
+
+ if ( gamestatsuploader )
+ {
+ gamestatsuploader->UploadGameStats(
+ STRING( gpGlobals->mapname ),
+ DOD_STATS_BLOB_VERSION,
+ uBlobSize,
+ pvBlobData );
+ }
+ }
+ }
+
+ void CDODGameRules::Stats_PlayerKill( int team, int cls )
+ {
+ Assert( cls >= 0 && cls <= 5 );
+
+ if ( cls >= 0 && cls <= 5 )
+ {
+ if ( team == TEAM_ALLIES )
+ m_iStatsKillsPerClass_Allies[cls]++;
+ else if ( team == TEAM_AXIS )
+ m_iStatsKillsPerClass_Axis[cls]++;
+ }
+ }
+
+ void CDODGameRules::Stats_PlayerCap( int team, int cls )
+ {
+ Assert( cls >= 0 && cls <= 5 );
+
+ if ( cls >= 0 && cls <= 5 )
+ {
+ if ( team == TEAM_ALLIES )
+ m_iStatsCapsPerClass_Allies[cls]++;
+ else if ( team == TEAM_AXIS )
+ m_iStatsCapsPerClass_Axis[cls]++;
+ }
+ }
+
+ void CDODGameRules::Stats_PlayerDefended( int team, int cls )
+ {
+ Assert( cls >= 0 && cls <= 5 );
+
+ if ( cls >= 0 && cls <= 5 )
+ {
+ if ( team == TEAM_ALLIES )
+ m_iStatsDefensesPerClass_Allies[cls]++;
+ else if ( team == TEAM_AXIS )
+ m_iStatsDefensesPerClass_Axis[cls]++;
+ }
+ }
+
+ void CDODGameRules::Stats_WeaponFired( int weaponID )
+ {
+ m_iWeaponShotsFired[weaponID]++;
+ }
+
+ void CDODGameRules::Stats_WeaponHit( int weaponID, float flDist )
+ {
+ m_iWeaponShotsHit[weaponID]++;
+
+ int bucket = Stats_WeaponDistanceToBucket( weaponID, flDist );
+ m_iWeaponDistanceBuckets[weaponID][bucket]++;
+ }
+
+ int CDODGameRules::Stats_WeaponDistanceToBucket( int weaponID, float flDist )
+ {
+ int bucket = 4;
+ int iDist = (int)flDist;
+
+ for ( int i=0;i<DOD_NUM_WEAPON_DISTANCE_BUCKETS-1;i++ )
+ {
+ if ( iDist < iWeaponBucketDistances[i] )
+ {
+ bucket = i;
+ break;
+ }
+ }
+
+ return bucket;
+ }
+
+
+ //-----------------------------------------------------------------------------
+ // Purpose: DoD Specific Client Commands
+ // Input :
+ // Output :
+ //-----------------------------------------------------------------------------
+ bool CDODGameRules::ClientCommand( CBaseEntity *pEdict, const CCommand &args )
+ {
+ CDODPlayer *pPlayer = ToDODPlayer( pEdict );
+ const char *pcmd = args[0];
+#ifdef DEBUG
+ if ( FStrEq( pcmd, "teamwin" ) )
+ {
+ if ( args.ArgC() < 2 )
+ return true;
+
+ SetWinningTeam( atoi( args[1] ) );
+
+ return true;
+ }
+ else
+#endif
+ // Handle some player commands here as they relate more directly to gamerules state
+ if ( FStrEq( pcmd, "nextmap" ) )
+ {
+ CDODPlayer *pDODPlayer = ToDODPlayer(pPlayer);
+
+ if ( pDODPlayer->m_flNextTimeCheck < gpGlobals->curtime )
+ {
+ char szNextMap[32];
+
+ if ( nextlevel.GetString() && *nextlevel.GetString() )
+ {
+ Q_strncpy( szNextMap, nextlevel.GetString(), sizeof( szNextMap ) );
+ }
+ else
+ {
+ GetNextLevelName( szNextMap, sizeof( szNextMap ) );
+ }
+
+ ClientPrint( pPlayer, HUD_PRINTTALK, "#game_nextmap", szNextMap);
+
+ pDODPlayer->m_flNextTimeCheck = gpGlobals->curtime + 1;
+ }
+
+ return true;
+ }
+ else if ( FStrEq( pcmd, "timeleft" ) )
+ {
+ CDODPlayer *pDODPlayer = ToDODPlayer(pPlayer);
+
+ if ( pDODPlayer->m_flNextTimeCheck < gpGlobals->curtime )
+ {
+ if ( mp_timelimit.GetInt() > 0 )
+ {
+ int iTimeLeft = GetTimeLeft();
+
+ char szMinutes[5];
+ char szSeconds[3];
+
+ if ( iTimeLeft <= 0 )
+ {
+ Q_snprintf( szMinutes, sizeof(szMinutes), "0" );
+ Q_snprintf( szSeconds, sizeof(szSeconds), "00" );
+ }
+ else
+ {
+ Q_snprintf( szMinutes, sizeof(szMinutes), "%d", iTimeLeft / 60 );
+ Q_snprintf( szSeconds, sizeof(szSeconds), "%02d", iTimeLeft % 60 );
+ }
+
+ ClientPrint( pPlayer, HUD_PRINTTALK, "#game_time_left1", szMinutes, szSeconds );
+ }
+ else
+ {
+ ClientPrint( pPlayer, HUD_PRINTTALK, "#game_time_left2" );
+ }
+
+ CDODPlayer *pDODPlayer = ToDODPlayer(pPlayer);
+ pDODPlayer->m_flNextTimeCheck = gpGlobals->curtime + 1;
+ }
+ return true;
+ }
+ else if ( pPlayer->ClientCommand( args ) )
+ {
+ return true;
+ }
+ else if ( BaseClass::ClientCommand( pEdict, args ) )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ void CDODGameRules::CheckChatForReadySignal( CDODPlayer *pPlayer, const char *chatmsg )
+ {
+ if( m_bAwaitingReadyRestart && FStrEq( chatmsg, mp_clan_ready_signal.GetString() ) )
+ {
+ if( !m_bHeardAlliesReady && pPlayer->GetTeamNumber() == TEAM_ALLIES )
+ {
+ m_bHeardAlliesReady = true;
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_allies_ready" );
+ if ( event )
+ gameeventmanager->FireEvent( event );
+ }
+ else if( !m_bHeardAxisReady && pPlayer->GetTeamNumber() == TEAM_AXIS )
+ {
+ m_bHeardAxisReady = true;
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_axis_ready" );
+ if ( event )
+ gameeventmanager->FireEvent( event );
+ }
+ }
+ }
+
+ int CDODGameRules::SelectDefaultTeam()
+ {
+ int team = TEAM_UNASSIGNED;
+
+ CDODTeam *pAllies = GetGlobalDODTeam(TEAM_ALLIES);
+ CDODTeam *pAxis = GetGlobalDODTeam(TEAM_AXIS);
+
+ int iNumAllies = pAllies->GetNumPlayers();
+ int iNumAxis = pAxis->GetNumPlayers();
+
+ int iAlliesRoundsWon = pAllies->GetRoundsWon();
+ int iAxisRoundsWon = pAxis->GetRoundsWon();
+
+ int iAlliesPoints = pAllies->GetScore();
+ int iAxisPoints = pAxis->GetScore();
+
+ // Choose the team that's lacking players
+ if ( iNumAllies < iNumAxis )
+ {
+ team = TEAM_ALLIES;
+ }
+ else if ( iNumAllies > iNumAxis )
+ {
+ team = TEAM_AXIS;
+ }
+ // Choose the team that's losing
+ else if ( iAlliesRoundsWon < iAxisRoundsWon )
+ {
+ team = TEAM_ALLIES;
+ }
+ else if ( iAlliesRoundsWon > iAxisRoundsWon )
+ {
+ team = TEAM_AXIS;
+ }
+ // choose the team with fewer points
+ else if ( iAlliesPoints < iAxisPoints )
+ {
+ team = TEAM_ALLIES;
+ }
+ else if ( iAlliesPoints > iAxisPoints )
+ {
+ team = TEAM_AXIS;
+ }
+ else
+ {
+ // Teams and scores are equal, pick a random team
+ team = ( random->RandomInt(0,1) == 0 ) ? TEAM_ALLIES : TEAM_AXIS;
+ }
+
+ if ( TeamFull( team ) )
+ {
+ // Pick the opposite team
+ if ( team == TEAM_ALLIES )
+ {
+ team = TEAM_AXIS;
+ }
+ else
+ {
+ team = TEAM_ALLIES;
+ }
+
+ // No choices left
+ if ( TeamFull( team ) )
+ return TEAM_UNASSIGNED;
+ }
+
+ return team;
+ }
+
+ bool CDODGameRules::TeamFull( int team_id )
+ {
+ switch ( team_id )
+ {
+ case TEAM_ALLIES:
+ {
+ int iNumAllies = GetGlobalDODTeam(TEAM_ALLIES)->GetNumPlayers();
+ return iNumAllies >= m_iSpawnPointCount_Allies;
+ }
+ case TEAM_AXIS:
+ {
+ int iNumAxis = GetGlobalDODTeam(TEAM_AXIS)->GetNumPlayers();
+ return iNumAxis >= m_iSpawnPointCount_Axis;
+ }
+ }
+
+ return false;
+ }
+
+
+ //-----------------------------------------------------------------------------
+ // Purpose: Player has just spawned. Equip them.
+ //-----------------------------------------------------------------------------
+
+ // return a multiplier that should adjust the damage done by a blast at position vecSrc to something at the position
+ // vecEnd. This will take into account the density of an entity that blocks the line of sight from one position to
+ // the other.
+ //
+ // this algorithm was taken from the HL2 version of RadiusDamage.
+ float CDODGameRules::GetExplosionDamageAdjustment(Vector & vecSrc, Vector & vecEnd, CBaseEntity *pTarget, CBaseEntity *pEntityToIgnore)
+ {
+ float retval = 0.0;
+ trace_t tr;
+
+ UTIL_TraceLine(vecSrc, vecEnd, MASK_SHOT, pEntityToIgnore, COLLISION_GROUP_NONE, &tr);
+
+ Assert( pTarget );
+
+ // its a hit if we made it to the dest, or if we hit another part of the target on the way
+ if (tr.fraction == 1.0 || tr.m_pEnt == pTarget )
+ {
+ retval = 1.0;
+ }
+ else if (!(tr.DidHitWorld()) && (tr.m_pEnt != NULL) && (tr.m_pEnt->GetOwnerEntity() != pEntityToIgnore))
+ {
+ // if we didn't hit world geometry perhaps there's still damage to be done here.
+
+ CBaseEntity *blockingEntity = tr.m_pEnt;
+
+ // check to see if this part of the player is visible if entities are ignored.
+ UTIL_TraceLine(vecSrc, vecEnd, CONTENTS_SOLID, NULL, COLLISION_GROUP_NONE, &tr);
+
+ if (tr.fraction == 1.0)
+ {
+ if ((blockingEntity != NULL) && (blockingEntity->VPhysicsGetObject() != NULL))
+ {
+ int nMaterialIndex = blockingEntity->VPhysicsGetObject()->GetMaterialIndex();
+
+ float flDensity;
+ float flThickness;
+ float flFriction;
+ float flElasticity;
+
+ physprops->GetPhysicsProperties( nMaterialIndex, &flDensity,
+ &flThickness, &flFriction, &flElasticity );
+
+ const float ONE_OVER_DENSITY_ABSORB_ALL_DAMAGE = ( 1.0 / 3000.0 );
+ float scale = flDensity * ONE_OVER_DENSITY_ABSORB_ALL_DAMAGE;
+
+ if ((scale >= 0.0) && (scale < 1.0))
+ {
+ retval = 1.0 - scale;
+ }
+ else if (scale < 0.0)
+ {
+ // should never happen, but just in case.
+ retval = 1.0;
+ }
+ }
+ else
+ {
+ retval = 0.75; // we're blocked by something that isn't an entity with a physics module or world geometry, just cut damage in half for now.
+ }
+ }
+ }
+
+ return retval;
+ }
+
+ // returns the percentage of the player that is visible from the given point in the world.
+ // return value is between 0 and 1.
+ float CDODGameRules::GetAmountOfEntityVisible(Vector & vecSrc, CBaseEntity *entity, CBaseEntity *pIgnoreEntity )
+ {
+ float retval = 0.0;
+
+ Vector vecHullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN;
+
+ const float damagePercentageChest = 0.40;
+ const float damagePercentageHead = 0.30;
+ const float damagePercentageFoot = 0.10; // x 2
+ const float damagePercentageHand = 0.05; // x 2
+
+ if (!(entity->IsPlayer()))
+ {
+ // the entity is not a player, so the damage is all or nothing.
+ Vector vecTarget;
+ vecTarget = entity->BodyTarget(vecSrc, false);
+
+ return GetExplosionDamageAdjustment(vecSrc, vecTarget, entity, pIgnoreEntity);
+ }
+
+ CDODPlayer *player = ToDODPlayer(entity);
+
+ /*
+ new, sane method
+ */
+
+ static int iRHandIndex = 0;
+ static int iLHandIndex = 0;
+ static int iHeadIndex = 0;
+ static int iChestIndex = 0;
+ static int iRFootIndex = 0;
+ static int iLFootIndex = 0;
+
+ static bool bInitializedBones = false;
+
+ if ( !bInitializedBones )
+ {
+ iRHandIndex = player->LookupBone( "ValveBiped.Bip01_R_Hand" );
+ iLHandIndex = player->LookupBone( "ValveBiped.Bip01_L_Hand" );
+ iHeadIndex = player->LookupBone( "ValveBiped.Bip01_Head1" );
+ iChestIndex = player->LookupBone( "ValveBiped.Bip01_Spine2" );
+ iRFootIndex = player->LookupBone( "ValveBiped.Bip01_R_Foot" );
+ iLFootIndex = player->LookupBone( "ValveBiped.Bip01_L_Foot" );
+
+ Assert( iRHandIndex != -1 );
+ Assert( iLHandIndex != -1 );
+ Assert( iHeadIndex != -1 );
+ Assert( iChestIndex != -1 );
+ Assert( iRFootIndex != -1 );
+ Assert( iLFootIndex != -1 );
+
+ bInitializedBones = true;
+ }
+
+#ifdef _DEBUG
+ // verify that these bone indeces don't change
+ int checkBoneIndex = player->LookupBone( "ValveBiped.Bip01_R_Hand" );
+ Assert( checkBoneIndex == iRHandIndex );
+#endif
+
+
+ QAngle dummyAngle;
+
+ Vector vecRHand;
+ player->GetBonePosition( iRHandIndex, vecRHand, dummyAngle );
+
+ Vector vecLHand;
+ player->GetBonePosition( iLHandIndex, vecLHand, dummyAngle );
+
+ Vector vecHead;
+ player->GetBonePosition( iHeadIndex, vecHead, dummyAngle );
+
+ Vector vecChest;
+ player->GetBonePosition( iChestIndex, vecChest, dummyAngle );
+
+ Vector vecRFoot;
+ player->GetBonePosition( iRFootIndex, vecRFoot, dummyAngle );
+
+ Vector vecLFoot;
+ player->GetBonePosition( iLFootIndex, vecLFoot, dummyAngle );
+
+ // right hand
+ float damageAdjustment = GetExplosionDamageAdjustment(vecSrc, vecRHand, player, pIgnoreEntity );
+ retval += (damagePercentageHand * damageAdjustment);
+
+/*
+ Msg( "right hand: %.1f\n", damageAdjustment );
+ NDebugOverlay::Line( vecSrc, vecRHand,
+ (int)(damageAdjustment * 255.0),
+ (int)((1.0 - damageAdjustment) * 255.0),
+ 0,
+ true,
+ 10 );*/
+
+
+ // left hand
+ damageAdjustment = GetExplosionDamageAdjustment(vecSrc, vecLHand, player, pIgnoreEntity );
+ retval += (damagePercentageHand * damageAdjustment);
+
+/*
+ Msg( "left hand: %.1f\n", damageAdjustment );
+ NDebugOverlay::Line( vecSrc, vecLHand,
+ (int)(damageAdjustment * 255.0),
+ (int)((1.0 - damageAdjustment) * 255.0),
+ 0,
+ true,
+ 10 );*/
+
+
+ // head
+ damageAdjustment = GetExplosionDamageAdjustment(vecSrc, vecHead, player, pIgnoreEntity );
+ retval += (damagePercentageHead * damageAdjustment);
+
+/*
+ Msg( "head: %.1f\n", damageAdjustment );
+ NDebugOverlay::Line( vecSrc, vecHead,
+ (int)(damageAdjustment * 255.0),
+ (int)((1.0 - damageAdjustment) * 255.0),
+ 0,
+ true,
+ 10 );*/
+
+
+ // chest
+ damageAdjustment = GetExplosionDamageAdjustment(vecSrc, vecChest, player, pIgnoreEntity );
+ retval += (damagePercentageChest * damageAdjustment);
+
+/*
+ Msg( "chest: %.1f\n", damageAdjustment );
+ NDebugOverlay::Line( vecSrc, vecChest,
+ (int)(damageAdjustment * 255.0),
+ (int)((1.0 - damageAdjustment) * 255.0),
+ 0,
+ true,
+ 10 );*/
+
+
+ // right foot
+ damageAdjustment = GetExplosionDamageAdjustment(vecSrc, vecRFoot, player, pIgnoreEntity );
+ retval += (damagePercentageFoot * damageAdjustment);
+
+/*
+ Msg( "right foot: %.1f\n", damageAdjustment );
+ NDebugOverlay::Line( vecSrc, vecRFoot,
+ (int)(damageAdjustment * 255.0),
+ (int)((1.0 - damageAdjustment) * 255.0),
+ 0,
+ true,
+ 10 );*/
+
+
+ // left foot
+ damageAdjustment = GetExplosionDamageAdjustment(vecSrc, vecRFoot, player, pIgnoreEntity );
+ retval += (damagePercentageFoot * damageAdjustment);
+
+/*
+ Msg( "left foot: %.1f\n", damageAdjustment );
+ NDebugOverlay::Line( vecSrc, vecRFoot,
+ (int)(damageAdjustment * 255.0),
+ (int)((1.0 - damageAdjustment) * 255.0),
+ 0,
+ true,
+ 10 );*/
+
+
+// Msg( "total: %.1f\n", retval );
+
+ return retval;
+ }
+
+ void CDODGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore )
+ {
+ RadiusDamage( info, vecSrcIn, flRadius, iClassIgnore, pEntityIgnore, false );
+ }
+
+ ConVar r_visualizeExplosion( "r_visualizeExplosion", "0", FCVAR_CHEAT );
+
+ void CDODGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore, bool bIgnoreWorld /* = false */ )
+ {
+ CBaseEntity *pEntity = NULL;
+ trace_t tr;
+ float flAdjustedDamage, falloff;
+ Vector vecSpot;
+ Vector vecToTarget;
+
+ Vector vecSrc = vecSrcIn;
+
+ float flDamagePercentage;
+
+ if ( flRadius )
+ falloff = info.GetDamage() / flRadius;
+ else
+ falloff = 1.0;
+
+ vecSrc.z += 1;// in case grenade is lying on the ground
+
+ if ( r_visualizeExplosion.GetBool() )
+ {
+ float flLethalRange = ( info.GetDamage() - 100 ) / falloff;
+ float flHalfDamageRange = ( info.GetDamage() - 50 ) / falloff;
+ float flZeroDamageRange = ( info.GetDamage() ) / falloff;
+
+ // draw a red sphere representing the kill area
+ Vector dest = vecSrc;
+ dest.x += flLethalRange;
+
+ NDebugOverlay::HorzArrow( vecSrc, dest, 10, 255, 0, 0, 255, true, 10.0 );
+
+ // yellow for 50 damage
+ dest = vecSrc;
+ dest.x += flHalfDamageRange;
+
+ NDebugOverlay::HorzArrow( vecSrc, dest, 10, 255, 255, 0, 255, true, 10.0 );
+
+ // green for > 0 damage
+ dest = vecSrc;
+ dest.x += flZeroDamageRange;
+
+ NDebugOverlay::HorzArrow( vecSrc, dest, 10, 0, 255, 0, 255, true, 10.0 );
+ }
+
+ // iterate on all entities in the vicinity.
+ for ( CEntitySphereQuery sphere( vecSrc, flRadius ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
+ {
+ if ( pEntity->m_takedamage != DAMAGE_NO )
+ {
+ // UNDONE: this should check a damage mask, not an ignore
+ if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore )
+ continue;
+
+ if ( pEntity == pEntityIgnore )
+ continue;
+
+ // radius damage can only be blocked by the world
+ vecSpot = pEntity->BodyTarget( vecSrc );
+
+ if ( bIgnoreWorld )
+ {
+ flDamagePercentage = 1.0;
+ }
+ else
+ {
+ // get the percentage of the target entity that is visible from the
+ // explosion position.
+ flDamagePercentage = GetAmountOfEntityVisible(vecSrc, pEntity, info.GetInflictor() );
+ }
+
+ if (flDamagePercentage > 0.0)
+ {
+ // the explosion can 'see' this entity, so hurt them!
+ vecToTarget = ( vecSpot - vecSrc );
+
+ // decrease damage for an ent that's farther from the bomb.
+ flAdjustedDamage = vecToTarget.Length() * falloff;
+ flAdjustedDamage = info.GetDamage() - flAdjustedDamage;
+
+ flAdjustedDamage *= flDamagePercentage;
+
+ if ( flAdjustedDamage > 0 )
+ {
+ CTakeDamageInfo adjustedInfo = info;
+ adjustedInfo.SetDamage( flAdjustedDamage );
+
+ Vector dir = vecToTarget;
+ VectorNormalize( dir );
+
+ // If we don't have a damage force, manufacture one
+ if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin )
+ {
+ CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc, 1.5 /* explosion scale! */ );
+ }
+ else
+ {
+ // Assume the force passed in is the maximum force. Decay it based on falloff.
+ float flForce = adjustedInfo.GetDamageForce().Length() * falloff;
+ adjustedInfo.SetDamageForce( dir * flForce );
+ adjustedInfo.SetDamagePosition( vecSrc );
+ }
+
+ pEntity->TakeDamage( adjustedInfo );
+
+ // Now hit all triggers along the way that respond to damage...
+ pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, vecSpot, dir );
+ }
+ }
+ }
+ }
+ }
+
+ void CDODGameRules::RadiusStun( const CTakeDamageInfo &info, const Vector &vecSrc, float flRadius )
+ {
+ CBaseEntity *pEntity = NULL;
+ trace_t tr;
+ float flAdjustedDamage, falloff;
+ Vector vecSpot;
+ Vector vecToTarget;
+
+ if ( flRadius )
+ falloff = info.GetDamage() / flRadius;
+ else
+ falloff = 1.0;
+
+ // ok, now send updates to all clients
+ CBitVec< ABSOLUTE_PLAYER_LIMIT > playerbits;
+ playerbits.ClearAll();
+
+ // see which players are actually in the PVS of the grenade
+ engine->Message_DetermineMulticastRecipients( false, vecSrc, playerbits );
+
+ // Iterate through all players that made it into playerbits, that are inside the radius
+ // and give them stun damage
+ for ( int i=0;i<MAX_PLAYERS;i++ )
+ {
+ if ( playerbits.Get(i) == false )
+ continue;
+
+ pEntity = UTIL_EntityByIndex( i+1 );
+
+ if ( !pEntity || !pEntity->IsPlayer() )
+ continue;
+
+ if ( pEntity->m_takedamage != DAMAGE_NO )
+ {
+ // radius damage can only be blocked by the world
+ vecSpot = pEntity->BodyTarget( vecSrc );
+
+ // the explosion can 'see' this entity, so hurt them!
+ vecToTarget = ( vecSpot - vecSrc );
+
+ float flDist = vecToTarget.Length();
+
+ // make sure they are inside the radius
+ if ( flDist > flRadius )
+ continue;
+
+ // decrease damage for an ent that's farther from the bomb.
+ flAdjustedDamage = flDist * falloff;
+ flAdjustedDamage = info.GetDamage() - flAdjustedDamage;
+
+ if ( flAdjustedDamage > 0 )
+ {
+ CTakeDamageInfo adjustedInfo = info;
+ adjustedInfo.SetDamage( flAdjustedDamage );
+
+ pEntity->TakeDamage( adjustedInfo );
+ }
+ }
+ }
+ }
+
+ void CDODGameRules::Think()
+ {
+ if ( g_fGameOver ) // someone else quit the game already
+ {
+ // check to see if we should change levels now
+ if ( m_flIntermissionEndTime < gpGlobals->curtime )
+ {
+ ChangeLevel(); // intermission is over
+ }
+
+ return;
+ }
+
+ State_Think();
+
+ if ( gpGlobals->curtime > m_flNextPeriodicThink )
+ {
+ if ( CheckTimeLimit() )
+ return;
+
+ if ( CheckWinLimit() )
+ return;
+
+ CheckRestartRound();
+ CheckWarmup();
+ CheckPlayerPositions();
+
+ m_flNextPeriodicThink = gpGlobals->curtime + 1.0;
+ }
+
+ CGameRules::Think();
+ }
+
+ void CDODGameRules::GoToIntermission( void )
+ {
+ BaseClass::GoToIntermission();
+
+ // set all players to FL_FROZEN
+ for ( int i = 1; i <= MAX_PLAYERS; i++ )
+ {
+ CDODPlayer *pPlayer = ToDODPlayer( UTIL_PlayerByIndex( i ) );
+
+ if ( pPlayer )
+ {
+ pPlayer->AddFlag( FL_FROZEN );
+
+ pPlayer->StatEvent_UploadStats();
+ }
+ }
+
+ // Print out map stats to a text file
+ //WriteStatsFile( "stats.xml" );
+
+ State_Enter( STATE_GAME_OVER );
+ }
+
+ void CDODGameRules::SetInWarmup( bool bWarmup )
+ {
+ if( m_bInWarmup == bWarmup )
+ return;
+
+ m_bInWarmup = bWarmup;
+
+ if( m_bInWarmup )
+ {
+ m_flWarmupTimeEnds = gpGlobals->curtime + mp_warmup_time.GetFloat();
+ DevMsg( "Warmup_Begin\n" );
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_warmup_begins" );
+ if ( event )
+ gameeventmanager->FireEvent( event );
+ }
+ else
+ {
+ m_flWarmupTimeEnds = -1;
+ DevMsg( "Warmup_Ends\n" );
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_warmup_ends" );
+ if ( event )
+ gameeventmanager->FireEvent( event );
+ }
+ }
+
+ void CDODGameRules::CheckWarmup( void )
+ {
+ if( mp_restartwarmup.GetBool() )
+ {
+ if( m_bInWarmup )
+ {
+ m_flWarmupTimeEnds = gpGlobals->curtime + mp_warmup_time.GetFloat();
+ }
+ else
+ DODGameRules()->SetInWarmup( true );
+
+ mp_restartwarmup.SetValue( 0 );
+ }
+
+ if( mp_cancelwarmup.GetBool() )
+ {
+ DODGameRules()->SetInWarmup( false );
+ mp_cancelwarmup.SetValue( 0 );
+ }
+
+ if( m_bInWarmup )
+ {
+ // only exit the warmup if the time is up, and we are not in a round
+ // restart countdown already, and we are not waiting for a ready restart
+ if( gpGlobals->curtime > m_flWarmupTimeEnds && m_flRestartRoundTime < 0 && !m_bAwaitingReadyRestart )
+ {
+ // no need to end the warmup, the restart will end it automatically
+ //SetInWarmup( false );
+
+ m_flRestartRoundTime = gpGlobals->curtime; // reset asap
+ }
+ }
+ }
+
+ void CDODGameRules::CheckRestartRound( void )
+ {
+ if( mp_clan_readyrestart.GetBool() )
+ {
+ m_bAwaitingReadyRestart = true;
+ m_bHeardAlliesReady = false;
+ m_bHeardAxisReady = false;
+
+ const char *pszReadyString = mp_clan_ready_signal.GetString();
+
+ UTIL_ClientPrintAll( HUD_PRINTCONSOLE, "#clan_ready_rules", pszReadyString );
+ UTIL_ClientPrintAll( HUD_PRINTTALK, "#clan_ready_rules", pszReadyString );
+
+ // Don't let them put anything malicious in there
+ if( pszReadyString == NULL || Q_strlen(pszReadyString) > 16 )
+ {
+ pszReadyString = "ready";
+ }
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_ready_restart" );
+ if ( event )
+ gameeventmanager->FireEvent( event );
+
+ mp_clan_readyrestart.SetValue( 0 );
+
+ // cancel any restart round in progress
+ m_flRestartRoundTime = -1;
+ }
+
+ // Restart the game if specified by the server
+ int iRestartDelay = mp_clan_restartround.GetInt();
+
+ if ( iRestartDelay > 0 )
+ {
+ if ( iRestartDelay > 60 )
+ iRestartDelay = 60;
+
+ m_flRestartRoundTime = gpGlobals->curtime + iRestartDelay;
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_round_restart_seconds" );
+ if ( event )
+ {
+ event->SetInt( "seconds", iRestartDelay );
+ gameeventmanager->FireEvent( event );
+ }
+
+ mp_clan_restartround.SetValue( 0 );
+
+ // cancel any ready restart in progress
+ m_bAwaitingReadyRestart = false;
+ }
+ }
+
+ bool CDODGameRules::CheckTimeLimit()
+ {
+ if ( IsGameUnderTimeLimit() )
+ {
+ if( GetTimeLeft() <= 0 )
+ {
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_game_over" );
+ if ( event )
+ {
+ event->SetString( "reason", "Reached Time Limit" );
+ gameeventmanager->FireEvent( event );
+ }
+
+ SendTeamScoresEvent();
+
+ GoToIntermission();
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool CDODGameRules::CheckWinLimit()
+ {
+ // has one team won the specified number of rounds?
+
+ int iWinLimit = mp_winlimit.GetInt();
+
+ if ( iWinLimit > 0 )
+ {
+ CDODTeam *pAllies = GetGlobalDODTeam(TEAM_ALLIES);
+ CDODTeam *pAxis = GetGlobalDODTeam(TEAM_AXIS);
+
+ bool bAlliesWin = pAllies->GetRoundsWon() >= iWinLimit;
+ bool bAxisWin = pAxis->GetRoundsWon() >= iWinLimit;
+
+ if ( bAlliesWin || bAxisWin )
+ {
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_game_over" );
+ if ( event )
+ {
+ event->SetString( "reason", "Reached Round Win Limit" );
+ gameeventmanager->FireEvent( event );
+ }
+
+ GoToIntermission();
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void CDODGameRules::CheckPlayerPositions()
+ {
+ int i;
+ bool bUpdatePlayer[MAX_PLAYERS];
+ Q_memset( bUpdatePlayer, 0, sizeof(bUpdatePlayer) );
+
+ // check all players
+ for ( i=1; i<=gpGlobals->maxClients; i++ )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+
+ if ( !pPlayer )
+ continue;
+
+ Vector origin = pPlayer->GetAbsOrigin();
+
+ Vector2D pos( (int)(origin.x/4), (int)(origin.y/4) );
+
+ if ( pos == m_vecPlayerPositions[i-1] )
+ continue; // player didn't move enough
+
+ m_vecPlayerPositions[i-1] = pos;
+
+ bUpdatePlayer[i-1] = true; // player position changed since last time
+ }
+
+ // ok, now send updates to all clients
+ CBitVec< ABSOLUTE_PLAYER_LIMIT > playerbits;
+
+ for ( i=1; i<=gpGlobals->maxClients; i++ )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+
+ if ( !pPlayer )
+ continue;
+
+ if ( !pPlayer->IsConnected() )
+ continue;
+
+ CSingleUserRecipientFilter filter(pPlayer);
+
+ UserMessageBegin( filter, "UpdateRadar" );
+
+ playerbits.ClearAll();
+
+ // see what other players are in it's PVS, don't update them
+ engine->Message_DetermineMulticastRecipients( false, pPlayer->EyePosition(), playerbits );
+
+ for ( int i=0; i < gpGlobals->maxClients; i++ )
+ {
+ if ( playerbits.Get(i) )
+ continue; // this player is in his PVS, don't update radar pos
+
+ if ( !bUpdatePlayer[i] )
+ continue;
+
+ CBasePlayer *pOtherPlayer = UTIL_PlayerByIndex( i+1 );
+
+ if ( !pOtherPlayer )
+ continue; // nothing there
+
+ if ( pOtherPlayer == pPlayer )
+ continue; // dont update himself
+
+ if ( !pOtherPlayer->IsAlive() || pOtherPlayer->IsObserver() || !pOtherPlayer->IsConnected() )
+ continue; // don't update spectators or dead players
+
+ if ( pPlayer->GetTeamNumber() > TEAM_SPECTATOR )
+ {
+ // update only team mates if not a pure spectator
+ if ( pPlayer->GetTeamNumber() != pOtherPlayer->GetTeamNumber() )
+ continue;
+ }
+
+ WRITE_BYTE( i+1 ); // player entity index
+ WRITE_SBITLONG( m_vecPlayerPositions[i].x, COORD_INTEGER_BITS-1 );
+ WRITE_SBITLONG( m_vecPlayerPositions[i].y, COORD_INTEGER_BITS-1 );
+ WRITE_SBITLONG( AngleNormalize( pOtherPlayer->GetAbsAngles().y ), 9 );
+ }
+
+ WRITE_BYTE( 0 ); // end marker
+
+ MessageEnd(); // send message
+ }
+ }
+
+ Vector DropToGround(
+ CBaseEntity *pMainEnt,
+ const Vector &vPos,
+ const Vector &vMins,
+ const Vector &vMaxs )
+ {
+ trace_t trace;
+ UTIL_TraceHull( vPos, vPos + Vector( 0, 0, -500 ), vMins, vMaxs, MASK_SOLID, pMainEnt, COLLISION_GROUP_NONE, &trace );
+ return trace.endpos;
+ }
+
+
+ void TestSpawnPointType( const char *pEntClassName )
+ {
+ // Find the next spawn spot.
+ CBaseEntity *pSpot = gEntList.FindEntityByClassname( NULL, pEntClassName );
+
+ while( pSpot )
+ {
+ // check if pSpot is valid
+ if( g_pGameRules->IsSpawnPointValid( pSpot, NULL ) )
+ {
+ // the successful spawn point's location
+ NDebugOverlay::Box( pSpot->GetAbsOrigin(), VEC_HULL_MIN, VEC_HULL_MAX, 0, 255, 0, 100, 60 );
+
+ // drop down to ground
+ Vector GroundPos = DropToGround( NULL, pSpot->GetAbsOrigin(), VEC_HULL_MIN, VEC_HULL_MAX );
+
+ // the location the player will spawn at
+ NDebugOverlay::Box( GroundPos, VEC_HULL_MIN, VEC_HULL_MAX, 0, 0, 255, 100, 60 );
+
+ // draw the spawn angles
+ QAngle spotAngles = pSpot->GetLocalAngles();
+ Vector vecForward;
+ AngleVectors( spotAngles, &vecForward );
+ NDebugOverlay::HorzArrow( pSpot->GetAbsOrigin(), pSpot->GetAbsOrigin() + vecForward * 32, 10, 255, 0, 0, 255, true, 60 );
+ }
+ else
+ {
+ // failed spawn point location
+ NDebugOverlay::Box( pSpot->GetAbsOrigin(), VEC_HULL_MIN, VEC_HULL_MAX, 255, 0, 0, 100, 60 );
+ }
+
+ // increment pSpot
+ pSpot = gEntList.FindEntityByClassname( pSpot, pEntClassName );
+ }
+ }
+
+ void TestSpawns()
+ {
+ TestSpawnPointType( "info_player_allies" );
+ TestSpawnPointType( "info_player_axis" );
+ }
+ ConCommand cc_TestSpawns( "map_showspawnpoints", TestSpawns, "Dev - test the spawn points, draws for 60 seconds", FCVAR_CHEAT );
+
+ CBaseEntity *CDODGameRules::GetPlayerSpawnSpot( CBasePlayer *pPlayer )
+ {
+ // get valid spawn point
+ CBaseEntity *pSpawnSpot = pPlayer->EntSelectSpawnPoint();
+
+ // drop down to ground
+ Vector GroundPos = DropToGround( pPlayer, pSpawnSpot->GetAbsOrigin(), VEC_HULL_MIN, VEC_HULL_MAX );
+
+ // Move the player to the place it said.
+ pPlayer->Teleport( &GroundPos, &pSpawnSpot->GetLocalAngles(), &vec3_origin );
+ pPlayer->m_Local.m_vecPunchAngle = vec3_angle;
+
+ return pSpawnSpot;
+ }
+
+ // checks if the spot is clear of players
+ bool CDODGameRules::IsSpawnPointValid( CBaseEntity *pSpot, CBasePlayer *pPlayer )
+ {
+ if ( !pSpot->IsTriggered( pPlayer ) )
+ {
+ return false;
+ }
+
+ // Check if it is disabled by Enable/Disable
+ CSpawnPoint *pSpawnPoint = dynamic_cast< CSpawnPoint * >( pSpot );
+ if ( pSpawnPoint )
+ {
+ if ( pSpawnPoint->IsDisabled() )
+ {
+ return false;
+ }
+ }
+
+ Vector mins = GetViewVectors()->m_vHullMin;
+ Vector maxs = GetViewVectors()->m_vHullMax;
+
+ Vector vTestMins = pSpot->GetAbsOrigin() + mins;
+ Vector vTestMaxs = pSpot->GetAbsOrigin() + maxs;
+
+ // First test the starting origin.
+ return UTIL_IsSpaceEmpty( pPlayer, vTestMins, vTestMaxs );
+ }
+
+ void CDODGameRules::PlayerSpawn( CBasePlayer *p )
+ {
+ CDODPlayer *pPlayer = ToDODPlayer( p );
+
+ int team = pPlayer->GetTeamNumber();
+
+ if( team == TEAM_ALLIES || team == TEAM_AXIS )
+ {
+ int iPreviousPlayerClass = pPlayer->m_Shared.PlayerClass();
+
+ if( pPlayer->m_Shared.DesiredPlayerClass() == PLAYERCLASS_RANDOM )
+ {
+ ChooseRandomClass( pPlayer );
+ ClientPrint( pPlayer, HUD_PRINTTALK, "#game_now_as", GetPlayerClassName( pPlayer->m_Shared.PlayerClass(), team ) );
+ }
+ else
+ {
+ pPlayer->m_Shared.SetPlayerClass( pPlayer->m_Shared.DesiredPlayerClass() );
+ }
+
+ int playerclass = pPlayer->m_Shared.PlayerClass();
+
+ if ( playerclass != iPreviousPlayerClass )
+ {
+ // spawning as a new class, flush stats
+ pPlayer->StatEvent_UploadStats();
+ }
+
+ if( playerclass != PLAYERCLASS_UNDEFINED )
+ {
+ //Assert( PLAYERCLASS_UNDEFINED < playerclass && playerclass < NUM_PLAYERCLASSES );
+
+ int i;
+
+ CDODTeam *pTeam = GetGlobalDODTeam( team );
+ const CDODPlayerClassInfo &pClassInfo = pTeam->GetPlayerClassInfo( playerclass );
+
+ Assert( pClassInfo.m_iTeam == team );
+
+ pPlayer->SetModel( pClassInfo.m_szPlayerModel );
+ pPlayer->SetHitboxSet( 0 );
+
+ char buf[64];
+ int bufsize = sizeof(buf);
+
+ //Give weapons
+
+ // Primary weapon
+ Q_snprintf( buf, bufsize, "weapon_%s", WeaponIDToAlias(pClassInfo.m_iPrimaryWeapon) );
+ CBaseEntity *pPrimaryWpn = pPlayer->GiveNamedItem( buf );
+ Assert( pPrimaryWpn );
+
+ // Secondary weapon
+ CBaseEntity *pSecondaryWpn = NULL;
+ if ( pClassInfo.m_iSecondaryWeapon != WEAPON_NONE )
+ {
+ Q_snprintf( buf, bufsize, "weapon_%s", WeaponIDToAlias(pClassInfo.m_iSecondaryWeapon) );
+ pSecondaryWpn = pPlayer->GiveNamedItem( buf );
+ }
+
+ // Melee weapon
+ if ( pClassInfo.m_iMeleeWeapon )
+ {
+ Q_snprintf( buf, bufsize, "weapon_%s", WeaponIDToAlias(pClassInfo.m_iMeleeWeapon) );
+ pPlayer->GiveNamedItem( buf );
+ }
+
+ CWeaponDODBase *pWpn = NULL;
+
+ // Primary Ammo
+ pWpn = dynamic_cast<CWeaponDODBase *>(pPrimaryWpn);
+
+ if( pWpn )
+ {
+ int iNumClip = pWpn->GetDODWpnData().m_iDefaultAmmoClips - 1; //account for one clip in the gun
+ int iClipSize = pWpn->GetDODWpnData().iMaxClip1;
+ pPlayer->GiveAmmo( iNumClip * iClipSize, pWpn->GetDODWpnData().szAmmo1 );
+ }
+
+ // Secondary Ammo
+ if ( pSecondaryWpn )
+ {
+ pWpn = dynamic_cast<CWeaponDODBase *>(pSecondaryWpn);
+
+ if( pWpn )
+ {
+ int iNumClip = pWpn->GetDODWpnData().m_iDefaultAmmoClips - 1; //account for one clip in the gun
+ int iClipSize = pWpn->GetDODWpnData().iMaxClip1;
+ pPlayer->GiveAmmo( iNumClip * iClipSize, pWpn->GetDODWpnData().szAmmo1 );
+ }
+ }
+
+ // Grenade Type 1
+ if ( pClassInfo.m_iGrenType1 != WEAPON_NONE )
+ {
+ Q_snprintf( buf, bufsize, "weapon_%s", WeaponIDToAlias(pClassInfo.m_iGrenType1) );
+ for ( i=0;i<pClassInfo.m_iNumGrensType1;i++ )
+ {
+ pPlayer->GiveNamedItem( buf );
+ }
+ }
+
+ // Grenade Type 2
+ if ( pClassInfo.m_iGrenType2 != WEAPON_NONE )
+ {
+ Q_snprintf( buf, bufsize, "weapon_%s", WeaponIDToAlias(pClassInfo.m_iGrenType2) );
+ for ( i=0;i<pClassInfo.m_iNumGrensType2;i++ )
+ {
+ pPlayer->GiveNamedItem( buf );
+ }
+ }
+
+ pPlayer->Weapon_Switch( (CBaseCombatWeapon *)pPrimaryWpn );
+
+ // you get a helmet
+ pPlayer->SetBodygroup( BODYGROUP_HELMET, pClassInfo.m_iHelmetGroup );
+
+ // no jumpgear
+ pPlayer->SetBodygroup( BODYGROUP_JUMPGEAR, BODYGROUP_JUMPGEAR_OFF );
+
+ pPlayer->SetMaxSpeed( 600 );
+
+ Assert( playerclass >= 0 && playerclass <= 5 );
+ if ( playerclass >= 0 && playerclass <= 5 )
+ {
+ if ( team == TEAM_ALLIES )
+ m_iStatsSpawnsPerClass_Allies[playerclass]++;
+ else if ( team == TEAM_AXIS )
+ m_iStatsSpawnsPerClass_Axis[playerclass]++;
+ }
+ }
+ else
+ {
+ Assert( !"Player spawning with PLAYERCLASS_UNDEFINED" );
+ pPlayer->SetModel( NULL );
+ }
+ }
+ }
+
+ const char *CDODGameRules::GetPlayerClassName( int cls, int team )
+ {
+ CDODTeam *pTeam = GetGlobalDODTeam( team );
+
+ if( cls == PLAYERCLASS_RANDOM )
+ {
+ return "#class_random";
+ }
+
+ if( cls < 0 || cls >= pTeam->GetNumPlayerClasses() )
+ {
+ Assert( false );
+ return NULL;
+ }
+
+ const CDODPlayerClassInfo &pClassInfo = pTeam->GetPlayerClassInfo( cls );
+
+ return pClassInfo.m_szPrintName;
+ }
+
+ void CDODGameRules::ChooseRandomClass( CDODPlayer *pPlayer )
+ {
+ int i;
+ int numChoices = 0;
+ int choices[16];
+ int firstclass = 0;
+
+ CDODTeam *pTeam = GetGlobalDODTeam( pPlayer->GetTeamNumber() );
+
+ int lastclass = pTeam->GetNumPlayerClasses();
+
+ int previousClass = pPlayer->m_Shared.PlayerClass();
+
+ // Compile a list of the classes that aren't full
+ for( i=firstclass;i<lastclass;i++ )
+ {
+ // don't join the same class twice in a row
+ if ( i == previousClass )
+ continue;
+
+ if( CanPlayerJoinClass( pPlayer, i ) )
+ {
+ choices[numChoices] = i;
+ numChoices++;
+ }
+ }
+
+ // If ALL the classes are full
+ if( numChoices == 0 )
+ {
+ Msg( "Random class found that all classes were full - ignoring class limits for this spawn\n" );
+
+ pPlayer->m_Shared.SetPlayerClass( random->RandomFloat( firstclass, lastclass ) );
+ }
+ else
+ {
+ // Choose a slot randomly
+ i = random->RandomInt( 0, numChoices-1 );
+
+ // We are now the class that was in that slot
+ pPlayer->m_Shared.SetPlayerClass( choices[i] );
+ }
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose: This function can be used to find a valid placement location for an entity.
+ // Given an origin to start looking from and a minimum radius to place the entity at,
+ // it will sweep out a circle around vOrigin and try to find a valid spot (on the ground)
+ // where mins and maxs will fit.
+ // Input : *pMainEnt - Entity to place
+ // &vOrigin - Point to search around
+ // fRadius - Radius to search within
+ // nTries - Number of tries to attempt
+ // &mins - mins of the Entity
+ // &maxs - maxs of the Entity
+ // &outPos - Return point
+ // Output : Returns true and fills in outPos if it found a spot.
+ //-----------------------------------------------------------------------------
+ bool EntityPlacementTest( CBaseEntity *pMainEnt, const Vector &vOrigin, Vector &outPos, bool bDropToGround )
+ {
+ // This function moves the box out in each dimension in each step trying to find empty space like this:
+ //
+ // X
+ // X X
+ // Step 1: X Step 2: XXX Step 3: XXXXX
+ // X X
+ // X
+ //
+
+ Vector mins, maxs;
+ pMainEnt->CollisionProp()->WorldSpaceAABB( &mins, &maxs );
+ mins -= pMainEnt->GetAbsOrigin();
+ maxs -= pMainEnt->GetAbsOrigin();
+
+ // Put some padding on their bbox.
+
+ Vector vTestMins = mins;
+ Vector vTestMaxs = maxs;
+
+ // First test the starting origin.
+ if ( UTIL_IsSpaceEmpty( pMainEnt, vOrigin + vTestMins, vOrigin + vTestMaxs ) )
+ {
+ if ( bDropToGround )
+ {
+ outPos = DropToGround( pMainEnt, vOrigin, vTestMins, vTestMaxs );
+ }
+ else
+ {
+ outPos = vOrigin;
+ }
+ return true;
+ }
+
+ Vector vDims = vTestMaxs - vTestMins;
+
+ // Keep branching out until we get too far.
+ int iCurIteration = 0;
+ int nMaxIterations = 15;
+
+ int offset = 0;
+ do
+ {
+ for ( int iDim=0; iDim < 2; iDim++ )
+ {
+ float flCurOffset = offset * vDims[iDim];
+
+ for ( int iSign=0; iSign < 2; iSign++ )
+ {
+ Vector vBase = vOrigin;
+ vBase[iDim] += (iSign*2-1) * flCurOffset;
+
+ if ( UTIL_IsSpaceEmpty( pMainEnt, vBase + vTestMins, vBase + vTestMaxs ) )
+ {
+ // Ensure that there is a clear line of sight from the spawnpoint entity to the actual spawn point.
+ // (Useful for keeping things from spawning behind walls near a spawn point)
+ trace_t tr;
+ UTIL_TraceLine( vOrigin, vBase, MASK_SOLID, pMainEnt, COLLISION_GROUP_NONE, &tr );
+
+ if ( tr.fraction != 1.0 )
+ {
+ continue;
+ }
+
+ if ( bDropToGround )
+ outPos = DropToGround( pMainEnt, vBase, vTestMins, vTestMaxs );
+ else
+ outPos = vBase;
+
+ return true;
+ }
+ }
+ }
+
+ ++offset;
+ } while ( iCurIteration++ < nMaxIterations );
+
+ // Warning( "EntityPlacementTest for ent %d:%s failed!\n", pMainEnt->entindex(), pMainEnt->GetClassname() );
+ return false;
+ }
+
+ bool CDODGameRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon )
+ {
+ //only allow one primary, one secondary and one melee
+ CWeaponDODBase *pWpn = (CWeaponDODBase *)pWeapon;
+
+ if( pWpn )
+ {
+ int type = pWpn->GetDODWpnData().m_WeaponType;
+
+ switch( type )
+ {
+ case WPN_TYPE_MELEE:
+ {
+#ifdef DEBUG
+ CWeaponDODBase *pMeleeWeapon = (CWeaponDODBase *)pPlayer->Weapon_GetSlot( WPN_SLOT_MELEE );
+ bool bHasMelee = ( pMeleeWeapon != NULL );
+
+ if( bHasMelee )
+ {
+ Assert( !"Why are we trying to add another melee?" );
+ return false;
+ }
+#endif
+ }
+ break;
+ case WPN_TYPE_PISTOL:
+ case WPN_TYPE_SIDEARM:
+ {
+#ifdef DEBUG
+ CWeaponDODBase *pSecondaryWeapon = (CWeaponDODBase *)pPlayer->Weapon_GetSlot( WPN_SLOT_SECONDARY );
+ bool bHasPistol = ( pSecondaryWeapon != NULL );
+
+ if( bHasPistol )
+ {
+ Assert( !"Why are we trying to add another pistol?" );
+ return false;
+ }
+#endif
+ }
+ break;
+
+ case WPN_TYPE_CAMERA:
+ return true;
+
+ case WPN_TYPE_RIFLE:
+ case WPN_TYPE_SNIPER:
+ case WPN_TYPE_SUBMG:
+ case WPN_TYPE_MG:
+ case WPN_TYPE_BAZOOKA:
+ {
+ //Don't pick up dropped weapons if we have one already
+ CWeaponDODBase *pPrimaryWeapon = (CWeaponDODBase *)pPlayer->Weapon_GetSlot( WPN_SLOT_PRIMARY );
+ bool bHasPrimary = ( pPrimaryWeapon != NULL );
+
+ if( bHasPrimary )
+ return false;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return BaseClass::CanHavePlayerItem( pPlayer, pWeapon );
+ }
+
+ void CDODGameRules::ResetMapTime( void )
+ {
+ m_flMapResetTime = gpGlobals->curtime;
+
+ // send an event with the time remaining until map change
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_map_time_remaining" );
+ if ( event )
+ {
+ event->SetInt( "seconds", GetTimeLeft() );
+ gameeventmanager->FireEvent( event );
+ }
+ }
+
+#endif
+
+bool CDODGameRules::ShouldCollide( int collisionGroup0, int collisionGroup1 )
+{
+ if ( collisionGroup0 > collisionGroup1 )
+ {
+ // swap so that lowest is always first
+ V_swap(collisionGroup0,collisionGroup1);
+ }
+
+ //Don't stand on COLLISION_GROUP_WEAPONs
+ if( collisionGroup0 == COLLISION_GROUP_PLAYER_MOVEMENT &&
+ collisionGroup1 == COLLISION_GROUP_WEAPON )
+ {
+ return false;
+ }
+
+ // TE shells don't collide with the player
+ if ( collisionGroup0 == COLLISION_GROUP_PLAYER &&
+ collisionGroup1 == DOD_COLLISIONGROUP_SHELLS )
+ {
+ return false;
+ }
+
+ // blocker walls only collide with players
+ if ( collisionGroup1 == DOD_COLLISIONGROUP_BLOCKERWALL )
+ return ( collisionGroup0 == COLLISION_GROUP_PLAYER ) || ( collisionGroup0 == COLLISION_GROUP_PLAYER_MOVEMENT );
+
+ return BaseClass::ShouldCollide( collisionGroup0, collisionGroup1 );
+}
+
+int CDODGameRules::GetSubTeam( int team )
+{
+ return SUBTEAM_NORMAL;
+}
+
+bool CDODGameRules::IsGameUnderTimeLimit( void )
+{
+ return ( mp_timelimit.GetInt() > 0 );
+}
+
+int CDODGameRules::GetTimeLeft( void )
+{
+ float flTimeLimit = mp_timelimit.GetInt() * 60;
+
+ Assert( flTimeLimit > 0 && "Should not call this function when !IsGameUnderTimeLimit" );
+
+ float flMapChangeTime = m_flMapResetTime + flTimeLimit;
+
+#ifndef CLIENT_DLL
+ // If the round timer is longer, let the round complete
+ if ( m_bUsingTimer && m_pRoundTimer )
+ {
+ float flTimerSeconds = m_pRoundTimer->GetTimeRemaining();
+ float flMapChangeSeconds = flMapChangeTime - gpGlobals->curtime;
+
+ // if the map timer is less than the round timer
+ // AND
+ // the round timer is less than 2 minutes
+
+
+ // If the map time for any reason goes beyond the end of the round, remove the flag
+ if ( flMapChangeSeconds > flTimerSeconds )
+ {
+ m_bChangeLevelOnRoundEnd = false;
+ }
+ else if ( m_bChangeLevelOnRoundEnd || flTimerSeconds < 120 )
+ {
+ // once this happens once in a round, use this until the round ends
+ // or else the round will end when a team captures an objective and adds time to above 120
+ m_bChangeLevelOnRoundEnd = true;
+
+ return (int)( flTimerSeconds );
+ }
+ }
+#endif
+
+ return ( (int)(flMapChangeTime - gpGlobals->curtime) );
+}
+
+int CDODGameRules::GetReinforcementTimerSeconds( int team, float flSpawnEligibleTime )
+{
+ // find the first wave that this player can fit in
+
+ float flWaveTime = -1;
+
+ switch( team )
+ {
+ case TEAM_ALLIES:
+ {
+ int i = m_iAlliesRespawnHead;
+
+ while( i != m_iAlliesRespawnTail )
+ {
+ if ( flSpawnEligibleTime < m_AlliesRespawnQueue[i] )
+ {
+ flWaveTime = m_AlliesRespawnQueue[i];
+ break;
+ }
+
+ i = ( i+1 ) % DOD_RESPAWN_QUEUE_SIZE;
+ }
+ }
+ break;
+ case TEAM_AXIS:
+ {
+ int i = m_iAxisRespawnHead;
+
+ while( i != m_iAxisRespawnTail )
+ {
+ if ( flSpawnEligibleTime < m_AxisRespawnQueue[i] )
+ {
+ flWaveTime = m_AxisRespawnQueue[i];
+ break;
+ }
+
+ i = ( i+1 ) % DOD_RESPAWN_QUEUE_SIZE;
+ }
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ return MAX( 0, (int)( flWaveTime - gpGlobals->curtime ) );
+}
+
+const CViewVectors* CDODGameRules::GetViewVectors() const
+{
+ return &g_DODViewVectors;
+}
+
+const CDODViewVectors *CDODGameRules::GetDODViewVectors() const
+{
+ return &g_DODViewVectors;
+}
+
+#ifndef CLIENT_DLL
+
+ extern ConVar dod_bonusround;
+
+ bool CDODGameRules::IsFriendlyFireOn( void )
+ {
+ // Never friendly fire in bonus round
+ if ( IsInBonusRound() )
+ {
+ return false;
+ }
+
+ return friendlyfire.GetBool();
+ }
+
+ bool CDODGameRules::IsInBonusRound( void )
+ {
+ return ( dod_bonusround.GetBool() == true && ( State_Get() == STATE_ALLIES_WIN || State_Get() == STATE_AXIS_WIN ) );
+ }
+
+ ConVar dod_showroundtransitions( "dod_showroundtransitions", "0", 0, "Show gamestate round transitions" );
+
+ void CDODGameRules::State_Transition( DODRoundState newState )
+ {
+ State_Leave();
+ State_Enter( newState );
+ }
+
+ void CDODGameRules::State_Enter( DODRoundState newState )
+ {
+ m_iRoundState = newState;
+ m_pCurStateInfo = State_LookupInfo( newState );
+
+ if ( dod_showroundtransitions.GetInt() > 0 )
+ {
+ if ( m_pCurStateInfo )
+ Msg( "DODRoundState: entering '%s'\n", m_pCurStateInfo->m_pStateName );
+ else
+ Msg( "DODRoundState: entering #%d\n", newState );
+ }
+
+ // Initialize the new state.
+ if ( m_pCurStateInfo && m_pCurStateInfo->pfnEnterState )
+ (this->*m_pCurStateInfo->pfnEnterState)();
+ }
+
+ void CDODGameRules::State_Leave()
+ {
+ if ( m_pCurStateInfo && m_pCurStateInfo->pfnLeaveState )
+ {
+ (this->*m_pCurStateInfo->pfnLeaveState)();
+ }
+ }
+
+
+ void CDODGameRules::State_Think()
+ {
+ if ( m_pCurStateInfo && m_pCurStateInfo->pfnThink )
+ {
+ (this->*m_pCurStateInfo->pfnThink)();
+ }
+ }
+
+
+ CDODRoundStateInfo* CDODGameRules::State_LookupInfo( DODRoundState state )
+ {
+ static CDODRoundStateInfo playerStateInfos[] =
+ {
+ { STATE_INIT, "STATE_INIT", &CDODGameRules::State_Enter_INIT, NULL, &CDODGameRules::State_Think_INIT },
+ { STATE_PREGAME, "STATE_PREGAME", &CDODGameRules::State_Enter_PREGAME, NULL, &CDODGameRules::State_Think_PREGAME },
+ { STATE_STARTGAME, "STATE_STARTGAME", &CDODGameRules::State_Enter_STARTGAME, NULL, &CDODGameRules::State_Think_STARTGAME },
+ { STATE_PREROUND, "STATE_PREROUND", &CDODGameRules::State_Enter_PREROUND, NULL, &CDODGameRules::State_Think_PREROUND },
+ { STATE_RND_RUNNING,"STATE_RND_RUNNING",&CDODGameRules::State_Enter_RND_RUNNING, NULL, &CDODGameRules::State_Think_RND_RUNNING },
+ { STATE_ALLIES_WIN, "STATE_ALLIES_WIN", &CDODGameRules::State_Enter_ALLIES_WIN, NULL, &CDODGameRules::State_Think_ALLIES_WIN },
+ { STATE_AXIS_WIN, "STATE_AXIS_WIN", &CDODGameRules::State_Enter_AXIS_WIN, NULL, &CDODGameRules::State_Think_AXIS_WIN },
+ { STATE_RESTART, "STATE_RESTART", &CDODGameRules::State_Enter_RESTART, NULL, &CDODGameRules::State_Think_RESTART },
+ { STATE_GAME_OVER, "STATE_GAME_OVER", NULL, NULL, NULL },
+ };
+
+ for ( int i=0; i < ARRAYSIZE( playerStateInfos ); i++ )
+ {
+ if ( playerStateInfos[i].m_iRoundState == state )
+ return &playerStateInfos[i];
+ }
+
+ return NULL;
+ }
+
+ extern ConVar sv_stopspeed;
+ extern ConVar sv_friction;
+
+ void CDODGameRules::State_Enter_INIT( void )
+ {
+ InitTeams();
+
+ sv_stopspeed.SetValue( 50.0f );
+ sv_friction.SetValue( 8.0f );
+
+ ResetMapTime();
+ }
+
+ void CDODGameRules::State_Think_INIT( void )
+ {
+ State_Transition( STATE_PREGAME );
+ }
+
+ void CDODGameRules::InitTeams( void )
+ {
+ Assert( g_Teams.Count() == 0 );
+
+ g_Teams.Purge(); // just in case
+
+ // Create the team managers
+ int i;
+ for ( i = 0; i < 2; i++ ) // Unassigned and Spectators
+ {
+ CTeam *pTeam = static_cast<CTeam*>(CreateEntityByName( "dod_team_manager" ));
+ pTeam->Init( sTeamNames[i], i );
+
+ g_Teams.AddToTail( pTeam );
+ }
+
+ // clear the player class data
+ ResetFilePlayerClassInfoDatabase();
+
+ CTeam *pAllies = static_cast<CTeam*>(CreateEntityByName( "dod_team_allies" ));
+ Assert( pAllies );
+ pAllies->Init( sTeamNames[TEAM_ALLIES], TEAM_ALLIES );
+ g_Teams.AddToTail( pAllies );
+
+ CTeam *pAxis = static_cast<CTeam*>(CreateEntityByName( "dod_team_axis" ));
+ Assert( pAxis );
+ pAxis->Init( sTeamNames[TEAM_AXIS], TEAM_AXIS );
+ g_Teams.AddToTail( pAxis );
+ }
+
+ // dod_control_point_master can take inputs to add time to the round timer
+ void CDODGameRules::AddTimerSeconds( int iSecondsToAdd )
+ {
+ if( m_bUsingTimer && m_pRoundTimer )
+ {
+ m_pRoundTimer->AddTimerSeconds( iSecondsToAdd );
+
+ float flTimerSeconds = m_pRoundTimer->GetTimeRemaining();
+
+ m_bPlayTimerWarning_1Minute = ( flTimerSeconds > 60 );
+ m_bPlayTimerWarning_2Minute = ( flTimerSeconds > 120 );
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_timer_time_added" );
+ if ( event )
+ {
+ event->SetInt( "seconds_added", iSecondsToAdd );
+ gameeventmanager->FireEvent( event );
+ }
+ }
+ }
+
+ int CDODGameRules::GetTimerSeconds( void )
+ {
+ if( m_bUsingTimer && m_pRoundTimer )
+ {
+ return m_pRoundTimer->GetTimeRemaining();
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ // PREGAME - the server is idle and waiting for enough
+ // players to start up again. When we find an active player
+ // go to STATE_STARTGAME
+ void CDODGameRules::State_Enter_PREGAME( void )
+ {
+ m_flNextPeriodicThink = gpGlobals->curtime + 0.1;
+
+ Load_EntText();
+ }
+
+ void CDODGameRules::State_Think_PREGAME( void )
+ {
+ CheckLevelInitialized();
+
+ if( CountActivePlayers() > 0 )
+ State_Transition( STATE_STARTGAME );
+ }
+
+ // STARTGAME - wait a bit and then spawn everyone into the
+ // preround
+ void CDODGameRules::State_Enter_STARTGAME( void )
+ {
+ m_flStateTransitionTime = gpGlobals->curtime + 5 * dod_enableroundwaittime.GetFloat();
+
+ m_bInitialSpawn = true;
+ }
+
+ void CDODGameRules::State_Think_STARTGAME()
+ {
+ if( gpGlobals->curtime > m_flStateTransitionTime )
+ {
+ if( mp_warmup_time.GetFloat() > 0 )
+ {
+ // go into warmup, reset at end of it
+ SetInWarmup( true );
+ }
+
+ State_Transition( STATE_PREROUND );
+ }
+ }
+
+ void CDODGameRules::State_Enter_PREROUND( void )
+ {
+ // Longer wait time if its the first round, let people join
+ if ( m_bInitialSpawn )
+ {
+ m_flStateTransitionTime = gpGlobals->curtime + 10 * dod_enableroundwaittime.GetFloat();
+ m_bInitialSpawn = false;
+ }
+ else
+ {
+ m_flStateTransitionTime = gpGlobals->curtime + 5 * dod_enableroundwaittime.GetFloat();
+ }
+
+ //Game rules may change, if a new one becomes mastered at the end of the last round
+ DetectGameRules();
+
+ //reset everything in the level
+ RoundRespawn();
+
+ // reset this now! If its reset at round restart, we lose all the players that died
+ // during the preround
+ m_iAlliesRespawnHead = 0;
+ m_iAlliesRespawnTail = 0;
+ m_iAxisRespawnHead = 0;
+ m_iAxisRespawnTail = 0;
+ m_iNumAlliesRespawnWaves = 0;
+ m_iNumAxisRespawnWaves = 0;
+
+ m_iLastAlliesCapEvent = CAP_EVENT_NONE;
+ m_iLastAxisCapEvent = CAP_EVENT_NONE;
+
+ //find all the control points, init the timer
+ CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "dod_control_point_master" );
+
+ if( !pEnt )
+ {
+ Warning( "No dod_control_point_master found in level - control points will not work as expected.\n" );
+ }
+
+ bool bFoundTimer = false;
+
+ while( pEnt )
+ {
+ variant_t emptyVariant;
+ pEnt->AcceptInput( "RoundInit", NULL, NULL, emptyVariant, 0 );
+
+ CControlPointMaster *pMaster = dynamic_cast<CControlPointMaster *>( pEnt );
+
+ if ( pMaster && pMaster->IsActive() )
+ {
+ if ( pMaster->IsUsingRoundTimer() )
+ {
+ bFoundTimer = true;
+
+ m_bUsingTimer = true;
+
+ int iTimerSeconds;
+
+ pMaster->GetTimerData( iTimerSeconds, m_iTimerWinTeam );
+
+ if ( m_iTimerWinTeam != TEAM_ALLIES && m_iTimerWinTeam != TEAM_AXIS )
+ {
+ Assert( !"Round timer win team can only be allies or axis!\n" );
+ }
+
+ // Timer starts paused
+ if ( !m_pRoundTimer.Get() )
+ {
+ m_pRoundTimer = ( CDODRoundTimer *) CreateEntityByName( "dod_round_timer" );
+ }
+
+ Assert( m_pRoundTimer );
+
+ if ( m_pRoundTimer )
+ {
+ m_pRoundTimer->SetTimeRemaining( iTimerSeconds );
+ m_pRoundTimer->PauseTimer();
+
+ m_bPlayTimerWarning_1Minute = ( iTimerSeconds > 60 );
+ m_bPlayTimerWarning_2Minute = ( iTimerSeconds > 120 );
+ }
+ }
+ }
+
+ pEnt = gEntList.FindEntityByClassname( pEnt, "dod_control_point_master" );
+ }
+
+ if ( bFoundTimer == false )
+ {
+ // No masters are active that require the round timer, destroy it
+ UTIL_Remove( m_pRoundTimer.Get() );
+ m_pRoundTimer = NULL;
+ }
+
+ //init the cap areas
+ pEnt = gEntList.FindEntityByClassname( NULL, "dod_capture_area" );
+ while( pEnt )
+ {
+ variant_t emptyVariant;
+ pEnt->AcceptInput( "RoundInit", NULL, NULL, emptyVariant, 0 );
+
+ pEnt = gEntList.FindEntityByClassname( pEnt, "dod_capture_area" );
+ }
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_round_start" );
+ if ( event )
+ gameeventmanager->FireEvent( event );
+
+ // figure out which teams are bombing
+ m_bAlliesAreBombing = false;
+ m_bAxisAreBombing = false;
+
+ pEnt = gEntList.FindEntityByClassname( NULL, "dod_bomb_target" );
+ while( pEnt )
+ {
+ CDODBombTarget *pTarget = dynamic_cast<CDODBombTarget *>( pEnt );
+
+ if ( pTarget && pTarget->State_Get() == BOMB_TARGET_ACTIVE )
+ {
+ switch( pTarget->GetBombingTeam() )
+ {
+ case TEAM_ALLIES:
+ m_bAlliesAreBombing = true;
+ break;
+ case TEAM_AXIS:
+ m_bAxisAreBombing = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ pEnt = gEntList.FindEntityByClassname( pEnt, "dod_bomb_target" );
+ }
+ }
+
+ void CDODGameRules::State_Think_PREROUND( void )
+ {
+ if( gpGlobals->curtime > m_flStateTransitionTime )
+ State_Transition( STATE_RND_RUNNING );
+
+ CheckRespawnWaves();
+ }
+
+ void CDODGameRules::State_Enter_RND_RUNNING( void )
+ {
+ //find all the control points, init the timer
+ CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "dod_control_point_master" );
+
+ while( pEnt )
+ {
+ variant_t emptyVariant;
+ pEnt->AcceptInput( "RoundStart", NULL, NULL, emptyVariant, 0 );
+
+ pEnt = gEntList.FindEntityByClassname( pEnt, "dod_control_point_master" );
+ }
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_round_active" );
+ if ( event )
+ gameeventmanager->FireEvent( event );
+
+ if( !IsInWarmup() )
+ PlayStartRoundVoice();
+
+ if ( m_bUsingTimer && m_pRoundTimer.Get() != NULL )
+ {
+ m_pRoundTimer->ResumeTimer();
+ }
+
+ m_bChangeLevelOnRoundEnd = false;
+ }
+
+ void CDODGameRules::State_Think_RND_RUNNING( void )
+ {
+ //Where the magic happens
+
+ if ( m_bUsingTimer && m_pRoundTimer )
+ {
+ float flSecondsRemaining = m_pRoundTimer->GetTimeRemaining();
+
+ if ( flSecondsRemaining <= 0 )
+ {
+ // if there is a bomb still on a timer, and that bomb has
+ // the potential to add time, then we don't end the game
+
+ bool bBombBlocksWin = false;
+
+ //find all the control points, init the timer
+ CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "dod_bomb_target" );
+
+ while( pEnt )
+ {
+ CDODBombTarget *pBomb = dynamic_cast<CDODBombTarget *>( pEnt );
+
+ // Find active bombs that have the potential to add round time
+ if ( pBomb && pBomb->State_Get() == BOMB_TARGET_ARMED )
+ {
+ if ( pBomb->GetTimerAddSeconds() > 0 )
+ {
+ // don't end the round until this bomb goes off or is disarmed
+ bBombBlocksWin = true;
+ break;
+ }
+
+ CControlPoint *pPoint = pBomb->GetControlPoint();
+ int iBombingTeam = pBomb->GetBombingTeam();
+
+ if ( pPoint && pPoint->GetBombsRemaining() <= 1 )
+ {
+ // find active dod_control_point_masters, ask them if this flag capping
+ // would end the game
+ CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "dod_control_point_master" );
+
+ while( pEnt )
+ {
+ CControlPointMaster *pMaster = dynamic_cast<CControlPointMaster *>( pEnt );
+
+ if ( pMaster->IsActive() )
+ {
+ // Check TeamOwnsAllPoints, while overriding this particular flag's owner
+ if ( pMaster->WouldNewCPOwnerWinGame( pPoint, iBombingTeam ) )
+ {
+ // This bomb may win the game, don't end the round.
+ bBombBlocksWin = true;
+ break;
+ }
+ }
+
+ pEnt = gEntList.FindEntityByClassname( pEnt, "dod_control_point_master" );
+ }
+ }
+ }
+
+ pEnt = gEntList.FindEntityByClassname( pEnt, "dod_bomb_target" );
+ }
+
+ if ( bBombBlocksWin == false )
+ {
+ SetWinningTeam( m_iTimerWinTeam );
+
+ // tell the dod_control_point_master to fire its outputs for the winning team!
+ // minor hackage - dod_gamerules should be responsible for team win events, not dod_cpm
+
+ //find all the control points, init the timer
+ CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "dod_control_point_master" );
+
+ while( pEnt )
+ {
+ CControlPointMaster *pMaster = dynamic_cast<CControlPointMaster *>( pEnt );
+
+ if ( pMaster->IsActive() )
+ {
+ pMaster->FireTeamWinOutput( m_iTimerWinTeam );
+ }
+
+ pEnt = gEntList.FindEntityByClassname( pEnt, "dod_control_point_master" );
+ }
+ }
+ }
+ else if ( flSecondsRemaining < 60.0 && m_bPlayTimerWarning_1Minute == true )
+ {
+ // play one minute warning
+ DevMsg( 1, "Timer Warning: 1 Minute Remaining\n" );
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_timer_flash" );
+ if ( event )
+ {
+ event->SetInt( "time_remaining", 60 );
+ gameeventmanager->FireEvent( event );
+ }
+
+ m_bPlayTimerWarning_1Minute = false;
+ }
+ else if ( flSecondsRemaining < 120.0 && m_bPlayTimerWarning_2Minute == true )
+ {
+ // play two minute warning
+ DevMsg( 1, "Timer Warning: 2 Minutes Remaining\n" );
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_timer_flash" );
+ if ( event )
+ {
+ event->SetInt( "time_remaining", 120 );
+ gameeventmanager->FireEvent( event );
+ }
+
+ m_bPlayTimerWarning_2Minute = false;
+ }
+ }
+
+ //if we don't find any active players, return to STATE_PREGAME
+ if( CountActivePlayers() <= 0 )
+ {
+ State_Transition( STATE_PREGAME );
+ return;
+ }
+
+ CheckRespawnWaves();
+
+ // check round restart
+ if( m_flRestartRoundTime > 0 && m_flRestartRoundTime < gpGlobals->curtime )
+ {
+ // time to restart!
+ State_Transition( STATE_RESTART );
+ m_flRestartRoundTime = -1;
+ }
+
+ // check ready restart
+ if( m_bAwaitingReadyRestart && m_bHeardAlliesReady && m_bHeardAxisReady )
+ {
+ //State_Transition( STATE_RESTART );
+ m_flRestartRoundTime = gpGlobals->curtime + 5;
+ m_bAwaitingReadyRestart = false;
+ }
+ }
+
+ void CDODGameRules::CheckRespawnWaves( void )
+ {
+ bool bDoFailSafeWaveCheck = false;
+
+ if ( m_flNextFailSafeWaveCheckTime < gpGlobals->curtime )
+ {
+ bDoFailSafeWaveCheck = true;
+ m_flNextFailSafeWaveCheckTime = gpGlobals->curtime + 3.0;
+ }
+
+ //Respawn Timers
+ if( m_iNumAlliesRespawnWaves > 0 )
+ {
+ if ( m_AlliesRespawnQueue[m_iAlliesRespawnHead] < gpGlobals->curtime )
+ {
+ DevMsg( "Wave: Respawning Allies\n" );
+
+ RespawnTeam( TEAM_ALLIES );
+
+ PopWaveTime( TEAM_ALLIES );
+ }
+ }
+ else if ( bDoFailSafeWaveCheck )
+ {
+ // if there are any allied people waiting to spawn, spawn them
+ FailSafeSpawnPlayersOnTeam( TEAM_ALLIES );
+ }
+
+ if( m_iNumAxisRespawnWaves > 0 )
+ {
+ if ( m_AxisRespawnQueue[m_iAxisRespawnHead] < gpGlobals->curtime )
+ {
+ DevMsg( "Wave: Respawning Axis\n" );
+
+ RespawnTeam( TEAM_AXIS );
+
+ PopWaveTime( TEAM_AXIS );
+ }
+ }
+ else if ( bDoFailSafeWaveCheck )
+ {
+ // if there are any axis people waiting to spawn, spawn them
+ FailSafeSpawnPlayersOnTeam( TEAM_AXIS );
+ }
+ }
+
+ void CDODGameRules::FailSafeSpawnPlayersOnTeam( int iTeam )
+ {
+ DODRoundState roundState = State_Get();
+
+ CDODTeam *pTeam = GetGlobalDODTeam( iTeam );
+ if ( pTeam )
+ {
+ int iNumPlayers = pTeam->GetNumPlayers();
+ for ( int i=0;i<iNumPlayers;i++ )
+ {
+ CDODPlayer *pPlayer = pTeam->GetDODPlayer(i);
+ if ( !pPlayer )
+ continue;
+
+ // if this player is waiting to spawn, spawn them
+
+ if ( pPlayer->IsAlive() )
+ continue;
+
+ if( pPlayer->m_Shared.DesiredPlayerClass() == PLAYERCLASS_UNDEFINED )
+ continue;
+
+ if ( gpGlobals->curtime < ( pPlayer->GetDeathTime() + DEATH_CAM_TIME ) )
+ continue;
+
+ if ( pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM )
+ continue;
+
+ if ( roundState != STATE_PREROUND && pPlayer->State_Get() == STATE_DEATH_ANIM )
+ continue;
+
+ // Respawn this player
+ pPlayer->DODRespawn();
+
+ Assert( !"This will happen, but see if we can figure out why we get here" );
+ }
+ }
+ }
+
+ //ALLIES WIN
+ void CDODGameRules::State_Enter_ALLIES_WIN( void )
+ {
+ float flTime = MAX( 5, dod_bonusroundtime.GetFloat() );
+
+ m_flStateTransitionTime = gpGlobals->curtime + flTime * dod_enableroundwaittime.GetFloat();
+
+ if ( m_bUsingTimer && m_pRoundTimer )
+ {
+ m_pRoundTimer->PauseTimer();
+ }
+ }
+
+ void CDODGameRules::State_Think_ALLIES_WIN( void )
+ {
+ if( gpGlobals->curtime > m_flStateTransitionTime )
+ {
+ State_Transition( STATE_PREROUND );
+ }
+ }
+
+ //AXIS WIN
+ void CDODGameRules::State_Enter_AXIS_WIN( void )
+ {
+ float flTime = MAX( 5, dod_bonusroundtime.GetFloat() );
+
+ m_flStateTransitionTime = gpGlobals->curtime + flTime * dod_enableroundwaittime.GetFloat();
+
+ if ( m_bUsingTimer && m_pRoundTimer )
+ {
+ m_pRoundTimer->PauseTimer();
+ }
+ }
+
+ void CDODGameRules::State_Think_AXIS_WIN( void )
+ {
+ if( gpGlobals->curtime > m_flStateTransitionTime )
+ {
+ State_Transition( STATE_PREROUND );
+ }
+ }
+
+ // manual restart
+ void CDODGameRules::State_Enter_RESTART( void )
+ {
+ // send scores
+ SendTeamScoresEvent();
+
+ // send restart event
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_restart_round" );
+ if ( event )
+ gameeventmanager->FireEvent( event );
+
+ SetInWarmup( false );
+
+ ResetScores();
+
+ // reset the round time
+ ResetMapTime();
+
+ State_Transition( STATE_PREROUND );
+ }
+
+ void CDODGameRules::SendTeamScoresEvent( void )
+ {
+ // send scores
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_team_scores" );
+
+ if ( event )
+ {
+ CDODTeam *pAllies = GetGlobalDODTeam( TEAM_ALLIES );
+ CDODTeam *pAxis = GetGlobalDODTeam( TEAM_AXIS );
+
+ Assert( pAllies && pAxis );
+
+ event->SetInt( "allies_caps", pAllies->GetRoundsWon() );
+ event->SetInt( "allies_tick", pAllies->GetScore() );
+ event->SetInt( "allies_players", pAllies->GetNumPlayers() );
+ event->SetInt( "axis_caps", pAxis->GetRoundsWon() );
+ event->SetInt( "axis_tick", pAxis->GetScore() );
+ event->SetInt( "axis_players", pAxis->GetNumPlayers() );
+
+ gameeventmanager->FireEvent( event );
+ }
+ }
+
+ void CDODGameRules::State_Think_RESTART( void )
+ {
+ Assert( 0 ); // should never get here, State_Enter_RESTART sets us into a different state
+ }
+
+ void CDODGameRules::ResetScores( void )
+ {
+ GetGlobalDODTeam( TEAM_ALLIES )->ResetScores();
+ GetGlobalDODTeam( TEAM_AXIS )->ResetScores();
+
+ CDODPlayer *pDODPlayer;
+
+ for( int i = 1; i <= gpGlobals->maxClients; i++ )
+ {
+ pDODPlayer = ToDODPlayer( UTIL_PlayerByIndex( i ) );
+
+ if (pDODPlayer == NULL)
+ continue;
+
+ if (FNullEnt( pDODPlayer->edict() ))
+ continue;
+
+ pDODPlayer->ResetScores();
+ }
+ }
+
+ ConVar dod_showcleanedupents( "dod_showcleanedupents", "0", 0, "Show entities that are removed on round respawn" );
+
+ // Utility function
+ bool FindInList( const char **pStrings, const char *pToFind )
+ {
+ int i = 0;
+ while ( pStrings[i][0] != 0 )
+ {
+ if ( Q_stricmp( pStrings[i], pToFind ) == 0 )
+ return true;
+ i++;
+ }
+
+ return false;
+ }
+
+ void CDODGameRules::CleanUpMap()
+ {
+ // Recreate all the map entities from the map data (preserving their indices),
+ // then remove everything else except the players.
+
+ if( dod_showcleanedupents.GetBool() )
+ {
+ Msg( "CleanUpMap\n===============\n" );
+ }
+
+ // Get rid of all entities except players.
+ CBaseEntity *pCur = gEntList.FirstEnt();
+ while ( pCur )
+ {
+ if ( !FindInList( s_PreserveEnts, pCur->GetClassname() ) )
+ {
+ if( dod_showcleanedupents.GetBool() )
+ {
+ Msg( "Removed Entity: %s\n", pCur->GetClassname() );
+ }
+ UTIL_Remove( pCur );
+ }
+
+ pCur = gEntList.NextEnt( pCur );
+ }
+
+ // Really remove the entities so we can have access to their slots below.
+ gEntList.CleanupDeleteList();
+
+ // Now reload the map entities.
+ class CDODMapEntityFilter : public IMapEntityFilter
+ {
+ public:
+ virtual bool ShouldCreateEntity( const char *pClassname )
+ {
+ // Don't recreate the preserved entities.
+ if ( !FindInList( s_PreserveEnts, pClassname ) )
+ {
+ return true;
+ }
+ else
+ {
+ // Increment our iterator since it's not going to call CreateNextEntity for this ent.
+ if ( m_iIterator != g_MapEntityRefs.InvalidIndex() )
+ m_iIterator = g_MapEntityRefs.Next( m_iIterator );
+
+ return false;
+ }
+ }
+
+
+ virtual CBaseEntity* CreateNextEntity( const char *pClassname )
+ {
+ if ( m_iIterator == g_MapEntityRefs.InvalidIndex() )
+ {
+ // This shouldn't be possible. When we loaded the map, it should have used
+ // CDODMapLoadEntityFilter, which should have built the g_MapEntityRefs list
+ // with the same list of entities we're referring to here.
+ Assert( false );
+ return NULL;
+ }
+ else
+ {
+ CMapEntityRef &ref = g_MapEntityRefs[m_iIterator];
+ m_iIterator = g_MapEntityRefs.Next( m_iIterator ); // Seek to the next entity.
+
+ if ( ref.m_iEdict == -1 || engine->PEntityOfEntIndex( ref.m_iEdict ) )
+ {
+ // Doh! The entity was delete and its slot was reused.
+ // Just use any old edict slot. This case sucks because we lose the baseline.
+ return CreateEntityByName( pClassname );
+ }
+ else
+ {
+ // Cool, the slot where this entity was is free again (most likely, the entity was
+ // freed above). Now create an entity with this specific index.
+ return CreateEntityByName( pClassname, ref.m_iEdict );
+ }
+ }
+ }
+
+ public:
+ int m_iIterator; // Iterator into g_MapEntityRefs.
+ };
+ CDODMapEntityFilter filter;
+ filter.m_iIterator = g_MapEntityRefs.Head();
+
+ // DO NOT CALL SPAWN ON info_node ENTITIES!
+
+ MapEntity_ParseAllEntities( engine->GetMapEntitiesString(), &filter, true );
+ }
+
+ int CDODGameRules::CountActivePlayers( void )
+ {
+ int i;
+ int count = 0;
+ CDODPlayer *pDODPlayer;
+
+ for (i = 1; i <= gpGlobals->maxClients; i++ )
+ {
+ pDODPlayer = ToDODPlayer( UTIL_PlayerByIndex( i ) );
+
+ if( pDODPlayer )
+ {
+ if( pDODPlayer->IsReadyToPlay() )
+ {
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ void CDODGameRules::RoundRespawn( void )
+ {
+ CleanUpMap();
+ RespawnAllPlayers();
+
+ // reset per-round scores for each player
+ for ( int i=0;i<MAX_PLAYERS;i++ )
+ {
+ CDODPlayer *pPlayer = ToDODPlayer( UTIL_PlayerByIndex( i ) );
+
+ if ( pPlayer )
+ {
+ pPlayer->ResetPerRoundStats();
+ }
+ }
+ }
+
+ typedef struct {
+ int iPlayerIndex;
+ int iScore;
+ } playerscore_t;
+
+ int PlayerScoreInfoSort( const playerscore_t *p1, const playerscore_t *p2 )
+ {
+ // check frags
+ if ( p1->iScore > p2->iScore )
+ return -1;
+ if ( p2->iScore > p1->iScore )
+ return 1;
+
+ // check index
+ if ( p1->iPlayerIndex < p2->iPlayerIndex )
+ return -1;
+
+ return 1;
+ }
+
+ // Store which event happened most recently, flag cap or bomb explode
+ void CDODGameRules::CapEvent( int event, int team )
+ {
+ switch( team )
+ {
+ case TEAM_ALLIES:
+ m_iLastAlliesCapEvent = event;
+ break;
+ case TEAM_AXIS:
+ m_iLastAxisCapEvent = event;
+ break;
+ }
+ }
+
+ void FillEventCategory( IGameEvent *event, int side, int category, CUtlVector<playerscore_t> &pList )
+ {
+ switch ( side )
+ {
+ case 0:
+ event->SetInt( "category_left", category );
+ break;
+ case 1:
+ event->SetInt( "category_right", category );
+ break;
+ }
+
+ static const char *pCategoryNames[2][6] =
+ {
+ {
+ "left_1",
+ "left_score_1",
+ "left_2",
+ "left_score_2",
+ "left_3",
+ "left_score_3"
+ },
+ {
+ "right_1",
+ "right_score_1",
+ "right_2",
+ "right_score_2",
+ "right_3",
+ "right_score_3"
+ }
+ };
+
+ int iNumInList = pList.Count();
+
+ if ( iNumInList > 0 )
+ {
+ event->SetInt( pCategoryNames[side][0], pList[0].iPlayerIndex );
+ event->SetInt( pCategoryNames[side][1], pList[0].iScore );
+ }
+ else
+ event->SetInt( pCategoryNames[side][0], 0 );
+
+ if ( iNumInList > 1 )
+ {
+ event->SetInt( pCategoryNames[side][2], pList[1].iPlayerIndex );
+ event->SetInt( pCategoryNames[side][3], pList[1].iScore );
+ }
+ else
+ event->SetInt( pCategoryNames[side][2], 0 );
+
+ if ( iNumInList > 2 )
+ {
+ event->SetInt( pCategoryNames[side][4], pList[2].iPlayerIndex );
+ event->SetInt( pCategoryNames[side][5], pList[2].iScore );
+ }
+ else
+ event->SetInt( pCategoryNames[side][4], 0 );
+ }
+
+ //Input for other entities to declare a round winner.
+ //Most often a dod_control_point_master saying that the
+ //round timer expired or that someone capped all the flags
+ void CDODGameRules::SetWinningTeam( int team )
+ {
+ if ( team != TEAM_ALLIES && team != TEAM_AXIS )
+ {
+ Assert( !"bad winning team set" );
+ return;
+ }
+
+ PlayWinSong(team);
+
+ GetGlobalDODTeam( team )->IncrementRoundsWon();
+
+ switch(team)
+ {
+ case TEAM_ALLIES:
+ {
+ State_Transition( STATE_ALLIES_WIN );
+ }
+ break;
+ case TEAM_AXIS:
+ {
+ State_Transition( STATE_AXIS_WIN );
+ }
+ break;
+ default:
+ break;
+ }
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_round_win" );
+ if ( event )
+ {
+ event->SetInt( "team", team );
+ gameeventmanager->FireEvent( event );
+ }
+
+ // if this was in colmar, and the losing team did not cap any points,
+ // the winners may have gotten an achievement
+ if ( FStrEq( STRING(gpGlobals->mapname), "dod_colmar" ) )
+ {
+ CControlPointMaster *pMaster = dynamic_cast<CControlPointMaster *>( gEntList.FindEntityByClassname( NULL, "dod_control_point_master" ) );
+
+ if ( pMaster )
+ {
+ // 1. losing team must not own any control points
+ // 2. for each point that the winning team owns, that takes bombs, it must still have 2 bombs required
+ bool bFlawlessVictory = true;
+
+ int iNumCP = pMaster->GetNumPoints();
+
+ for ( int i=0;i<iNumCP;i++ )
+ {
+ CControlPoint *pPoint = pMaster->GetCPByIndex(i);
+
+ if ( !pPoint || !pPoint->PointIsVisible() )
+ continue;
+
+ // if the enemy owns any visible points, not a flawless victory
+ if ( pPoint->GetOwner() != team )
+ {
+ bFlawlessVictory = false;
+ }
+
+ // 0 bombs remaining means we blew it up and now own it.
+ // 1 bomb remaining means we own it, but the other team blew it up a bit.
+ else if ( pPoint->GetBombsRequired() > 0 && pPoint->GetBombsRemaining() == 1 )
+ {
+ bFlawlessVictory = false;
+ }
+ }
+
+ if ( bFlawlessVictory )
+ {
+ GetGlobalDODTeam( team )->AwardAchievement( ACHIEVEMENT_DOD_COLMAR_DEFENSE );
+ }
+ }
+ }
+
+ // send team scores
+ SendTeamScoresEvent();
+
+ IGameEvent *winEvent = gameeventmanager->CreateEvent( "dod_win_panel" );
+
+ if ( winEvent )
+ {
+ // determine what categories to send
+
+ if ( m_bUsingTimer )
+ {
+ if ( team == m_iTimerWinTeam )
+ {
+ // timer expired, defenders win
+ // show total time that was defended
+ winEvent->SetBool( "show_timer_defend", true );
+ winEvent->SetInt( "timer_time", m_pRoundTimer->GetTimerMaxLength() );
+ }
+ else
+ {
+ // attackers win
+ // show time it took for them to win
+ winEvent->SetBool( "show_timer_attack", true );
+
+ int iTimeElapsed = m_pRoundTimer->GetTimerMaxLength() - (int)m_pRoundTimer->GetTimeRemaining();
+ winEvent->SetInt( "timer_time", iTimeElapsed );
+ }
+ }
+ else
+ {
+ winEvent->SetBool( "show_timer_attack", false );
+ winEvent->SetBool( "show_timer_defend", false );
+ }
+
+ int iLastEvent = ( team == TEAM_ALLIES ) ? m_iLastAlliesCapEvent : m_iLastAxisCapEvent;
+
+ winEvent->SetInt( "final_event", iLastEvent );
+
+ int i;
+ int index;
+
+ CUtlVector<playerscore_t> m_TopCappers;
+ CUtlVector<playerscore_t> m_TopDefenders;
+ CUtlVector<playerscore_t> m_TopBombers;
+ CUtlVector<playerscore_t> m_TopKills;
+
+ CDODTeam *pWinningTeam = GetGlobalDODTeam( team );
+
+ int iNumPlayers = pWinningTeam->GetNumPlayers();
+
+ for ( i=0;i<iNumPlayers;i++ )
+ {
+ CDODPlayer *pPlayer = dynamic_cast<CDODPlayer *>( pWinningTeam->GetPlayer(i) );
+
+ if ( pPlayer )
+ {
+ int iCaps = pPlayer->GetPerRoundCaps();
+ if ( iCaps )
+ {
+ index = m_TopCappers.AddToTail();
+ m_TopCappers[index].iPlayerIndex = pPlayer->entindex();
+ m_TopCappers[index].iScore = iCaps;
+ }
+
+ int iDefenses = pPlayer->GetPerRoundDefenses();
+ if ( iDefenses )
+ {
+ index = m_TopDefenders.AddToTail();
+ m_TopDefenders[index].iPlayerIndex = pPlayer->entindex();
+ m_TopDefenders[index].iScore = iDefenses;
+ }
+
+ // bombs
+ int iBombsDetonated = pPlayer->GetPerRoundBombsDetonated();
+ if ( iBombsDetonated )
+ {
+ index = m_TopBombers.AddToTail();
+ m_TopBombers[index].iPlayerIndex = pPlayer->entindex();
+ m_TopBombers[index].iScore = iBombsDetonated;
+ }
+
+ // kills
+ int iKills = pPlayer->GetPerRoundKills();
+ if ( iKills )
+ {
+ index = m_TopKills.AddToTail();
+ m_TopKills[index].iPlayerIndex = pPlayer->entindex();
+ m_TopKills[index].iScore = iKills;
+ }
+
+ pPlayer->StatEvent_RoundWin();
+ }
+ }
+
+ CDODTeam *pLosingTeam = GetGlobalDODTeam( ( team == TEAM_ALLIES ) ? TEAM_AXIS : TEAM_ALLIES );
+
+ iNumPlayers = pLosingTeam->GetNumPlayers();
+
+ for ( i=0;i<iNumPlayers;i++ )
+ {
+ CDODPlayer *pPlayer = dynamic_cast<CDODPlayer *>( pLosingTeam->GetPlayer(i) );
+
+ if ( pPlayer )
+ {
+ pPlayer->StatEvent_RoundLoss();
+ }
+ }
+
+ m_TopCappers.Sort( PlayerScoreInfoSort );
+ m_TopDefenders.Sort( PlayerScoreInfoSort );
+ m_TopBombers.Sort( PlayerScoreInfoSort );
+ m_TopKills.Sort( PlayerScoreInfoSort );
+
+ // Decide what two categories to show in the winpanel
+ // based on the gametype and which event have good information
+ // to show
+
+ int iCategoryPriority[8];
+ int pos = 0;
+
+ // Default is to show two blank sides
+ iCategoryPriority[pos++] = WINPANEL_TOP3_NONE;
+ iCategoryPriority[pos++] = WINPANEL_TOP3_NONE;
+
+ // Only show a category if it has information in it
+ if ( m_TopKills.Count() > 0 )
+ {
+ iCategoryPriority[pos++] = WINPANEL_TOP3_KILLERS;
+ }
+
+ if ( m_TopDefenders.Count() > 0 )
+ {
+ iCategoryPriority[pos++] = WINPANEL_TOP3_DEFENDERS;
+ }
+
+ if ( m_TopBombers.Count() > 0 )
+ {
+ iCategoryPriority[pos++] = WINPANEL_TOP3_BOMBERS;
+ }
+ else if ( m_TopCappers.Count() > 0 )
+ {
+ iCategoryPriority[pos++] = WINPANEL_TOP3_CAPPERS;
+ }
+
+ // Get the two most interesting
+ int iLeftCategory = iCategoryPriority[pos-1];
+ int iRightCategory = iCategoryPriority[pos-2];
+
+ switch( iLeftCategory )
+ {
+ case WINPANEL_TOP3_BOMBERS:
+ FillEventCategory( winEvent, 0, iLeftCategory, m_TopBombers );
+ break;
+ case WINPANEL_TOP3_CAPPERS:
+ FillEventCategory( winEvent, 0, iLeftCategory, m_TopCappers );
+ break;
+ case WINPANEL_TOP3_DEFENDERS:
+ FillEventCategory( winEvent, 0, iLeftCategory, m_TopDefenders );
+ break;
+ case WINPANEL_TOP3_KILLERS:
+ FillEventCategory( winEvent, 0, iLeftCategory, m_TopKills );
+ break;
+ case WINPANEL_TOP3_NONE:
+ default:
+ break;
+ }
+
+ switch( iRightCategory )
+ {
+ case WINPANEL_TOP3_BOMBERS:
+ FillEventCategory( winEvent, 1, iRightCategory, m_TopBombers );
+ break;
+ case WINPANEL_TOP3_CAPPERS:
+ FillEventCategory( winEvent, 1, iRightCategory, m_TopCappers );
+ break;
+ case WINPANEL_TOP3_DEFENDERS:
+ FillEventCategory( winEvent, 1, iRightCategory, m_TopDefenders );
+ break;
+ case WINPANEL_TOP3_KILLERS:
+ FillEventCategory( winEvent, 1, iRightCategory, m_TopKills );
+ break;
+ case WINPANEL_TOP3_NONE:
+ default:
+ break;
+ }
+
+ gameeventmanager->FireEvent( winEvent );
+ }
+ }
+
+ void TestWinpanel( void )
+ {
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_round_win" );
+ event->SetInt( "team", TEAM_ALLIES );
+
+ if ( event )
+ {
+ gameeventmanager->FireEvent( event );
+ }
+
+ IGameEvent *event2 = gameeventmanager->CreateEvent( "dod_point_captured" );
+ if ( event2 )
+ {
+ char cappers[9]; // pCappingPlayers is max length 8
+ int i;
+ for( i=0;i<1;i++ )
+ {
+ cappers[i] = (char)1;
+ }
+
+ cappers[i] = '\0';
+
+ // pCappingPlayers is a null terminated list of player indeces
+ event2->SetString( "cappers", cappers );
+ event2->SetBool( "bomb", true );
+
+ gameeventmanager->FireEvent( event2 );
+ }
+
+ IGameEvent *winEvent = gameeventmanager->CreateEvent( "dod_win_panel" );
+
+ if ( winEvent )
+ {
+ if ( 1 )
+ {
+ if ( 0 /*team == m_iTimerWinTeam */)
+ {
+ // timer expired, defenders win
+ // show total time that was defended
+ winEvent->SetBool( "show_timer_defend", true );
+ winEvent->SetInt( "timer_time", 0 /*m_pRoundTimer->GetTimerMaxLength() */);
+ }
+ else
+ {
+ // attackers win
+ // show time it took for them to win
+ winEvent->SetBool( "show_timer_attack", true );
+
+ int iTimeElapsed = 90; //m_pRoundTimer->GetTimerMaxLength() - (int)m_pRoundTimer->GetTimeRemaining();
+ winEvent->SetInt( "timer_time", iTimeElapsed );
+ }
+ }
+ else
+ {
+ winEvent->SetBool( "show_timer_attack", false );
+ winEvent->SetBool( "show_timer_defend", false );
+ }
+
+ int iLastEvent = CAP_EVENT_FLAG;
+
+ winEvent->SetInt( "final_event", iLastEvent );
+
+ CUtlVector<playerscore_t> m_TopKillers;
+ CUtlVector<playerscore_t> m_TopDefenders;
+ CUtlVector<playerscore_t> m_TopCappers;
+ CUtlVector<playerscore_t> m_TopBombers;
+
+ CDODPlayer *pPlayer = ToDODPlayer( UTIL_PlayerByIndex(1) );
+
+ if ( !pPlayer )
+ return;
+
+ int i = 0;
+ int index;
+ for ( i=0;i<3;i++ )
+ {
+ index = m_TopCappers.AddToTail();
+ m_TopCappers[index].iPlayerIndex = pPlayer->entindex();
+ m_TopCappers[index].iScore = pPlayer->GetPerRoundCaps() + 1;
+
+ index = m_TopDefenders.AddToTail();
+ m_TopDefenders[index].iPlayerIndex = pPlayer->entindex();
+ m_TopDefenders[index].iScore = pPlayer->GetPerRoundDefenses() + 1;
+
+ index = m_TopBombers.AddToTail();
+ m_TopBombers[index].iPlayerIndex = pPlayer->entindex();
+ m_TopBombers[index].iScore = pPlayer->GetPerRoundBombsDetonated() + 1;
+
+ index = m_TopKillers.AddToTail();
+ m_TopKillers[index].iPlayerIndex = pPlayer->entindex();
+ m_TopKillers[index].iScore = pPlayer->GetPerRoundKills() + 1;
+ }
+
+ m_TopCappers.Sort( PlayerScoreInfoSort );
+ m_TopDefenders.Sort( PlayerScoreInfoSort );
+
+ //FillEventCategory( winEvent, 0, WINPANEL_TOP3_KILLERS, m_TopKillers );
+ //FillEventCategory( winEvent, 1, WINPANEL_TOP3_DEFENDERS, m_TopDefenders );
+ FillEventCategory( winEvent, 0, WINPANEL_TOP3_BOMBERS, m_TopBombers );
+ FillEventCategory( winEvent, 1, WINPANEL_TOP3_CAPPERS, m_TopCappers );
+
+ gameeventmanager->FireEvent( winEvent );
+ }
+ }
+ ConCommand dod_test_winpanel( "dod_test_winpanel", TestWinpanel, "", FCVAR_CHEAT );
+
+ // bForceRespawn - respawn player even if dead or dying
+ // bTeam - if true, only respawn the passed team
+ // iTeam - team to respawn
+ void CDODGameRules::RespawnPlayers( bool bForceRespawn, bool bTeam /* = false */, int iTeam/* = TEAM_UNASSIGNED */ )
+ {
+ if ( bTeam )
+ {
+ if ( iTeam == TEAM_ALLIES )
+ DevMsg( 2, "Respawning Allies\n" );
+ else if ( iTeam == TEAM_AXIS )
+ DevMsg( 2, "Respawning Axis\n" );
+ else
+ Assert(!"Trying to respawn a strange team");
+ }
+
+ CDODPlayer *pPlayer;
+ for ( int i = 1; i <= gpGlobals->maxClients; i++ )
+ {
+ pPlayer = ToDODPlayer( UTIL_PlayerByIndex( i ) );
+
+ if ( !pPlayer )
+ continue;
+
+ // Check for team specific spawn
+ if ( bTeam && pPlayer->GetTeamNumber() != iTeam )
+ continue;
+
+ // players that haven't chosen a class can never spawn
+ if( pPlayer->m_Shared.DesiredPlayerClass() == PLAYERCLASS_UNDEFINED )
+ {
+ ClientPrint(pPlayer, HUD_PRINTTALK, "#game_will_spawn");
+ continue;
+ }
+
+ // If we aren't force respawning, don't respawn players that:
+ // - are alive
+ // - are still in the death anim stage of dying
+ if ( !bForceRespawn )
+ {
+ if ( pPlayer->IsAlive() )
+ continue;
+
+ if ( gpGlobals->curtime < ( pPlayer->GetDeathTime() + DEATH_CAM_TIME ) )
+ continue;
+
+ if ( pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM )
+ continue;
+
+ if ( State_Get() != STATE_PREROUND && pPlayer->State_Get() == STATE_DEATH_ANIM )
+ continue;
+ }
+
+ // Respawn this player
+ pPlayer->DODRespawn();
+ }
+ }
+
+ bool CDODGameRules::IsPlayerClassOnTeam( int cls, int team )
+ {
+ if( cls == PLAYERCLASS_RANDOM )
+ return true;
+
+ CDODTeam *pTeam = GetGlobalDODTeam( team );
+
+ return ( cls >= 0 && cls < pTeam->GetNumPlayerClasses() );
+ }
+
+ bool CDODGameRules::CanPlayerJoinClass( CDODPlayer *pPlayer, int cls )
+ {
+ if( cls == PLAYERCLASS_RANDOM )
+ {
+ return mp_allowrandomclass.GetBool();
+ }
+
+ if( ReachedClassLimit( pPlayer->GetTeamNumber(), cls ) )
+ return false;
+
+ return true;
+ }
+
+ bool CDODGameRules::ReachedClassLimit( int team, int cls )
+ {
+ Assert( cls != PLAYERCLASS_UNDEFINED );
+ Assert( cls != PLAYERCLASS_RANDOM );
+
+ // get the cvar
+ int iClassLimit = GetClassLimit( team, cls );
+
+ // count how many are active
+ int iClassExisting = CountPlayerClass( team, cls );
+
+ CDODTeam *pTeam = GetGlobalDODTeam( team );
+ const CDODPlayerClassInfo &pThisClassInfo = pTeam->GetPlayerClassInfo( cls );
+
+ if( mp_combinemglimits.GetBool() && pThisClassInfo.m_bClassLimitMGMerge )
+ {
+ // find the other classes that have "mergemgclasses"
+
+ for( int i=0; i<pTeam->GetNumPlayerClasses();i++ )
+ {
+ if( i != cls )
+ {
+ const CDODPlayerClassInfo &pClassInfo = pTeam->GetPlayerClassInfo( i );
+ if( pClassInfo.m_bClassLimitMGMerge )
+ {
+ // add that class' limits and counts
+ iClassLimit += GetClassLimit( team, i );
+ iClassExisting += CountPlayerClass( team, i );
+ }
+ }
+ }
+ }
+
+ if( iClassLimit > -1 && iClassExisting >= iClassLimit )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ int CDODGameRules::CountPlayerClass( int team, int cls )
+ {
+ int num = 0;
+ CDODPlayer *pDODPlayer;
+
+ for ( int i = 1; i <= gpGlobals->maxClients; i++ )
+ {
+ pDODPlayer = ToDODPlayer( UTIL_PlayerByIndex( i ) );
+
+ if (pDODPlayer == NULL)
+ continue;
+
+ if (FNullEnt( pDODPlayer->edict() ))
+ continue;
+
+ if( pDODPlayer->GetTeamNumber() != team )
+ continue;
+
+ if( pDODPlayer->m_Shared.DesiredPlayerClass() == cls )
+ num++;
+ }
+
+ return num;
+ }
+
+ int CDODGameRules::GetClassLimit( int team, int cls )
+ {
+ CDODTeam *pTeam = GetGlobalDODTeam( team );
+
+ Assert( pTeam );
+
+ const CDODPlayerClassInfo &pClassInfo = pTeam->GetPlayerClassInfo( cls );
+
+ int iClassLimit;
+
+ ConVar *pLimitCvar = ( ConVar * )cvar->FindVar( pClassInfo.m_szLimitCvar );
+
+ Assert( pLimitCvar );
+
+ if( pLimitCvar )
+ iClassLimit = pLimitCvar->GetInt();
+ else
+ iClassLimit = -1;
+
+ return iClassLimit;
+ }
+
+ void CDODGameRules::CheckLevelInitialized()
+ {
+ if ( !m_bLevelInitialized )
+ {
+ // Count the number of spawn points for each team
+ // This determines the maximum number of players allowed on each
+
+ CBaseEntity* ent = NULL;
+
+ m_iSpawnPointCount_Allies = 0;
+ m_iSpawnPointCount_Axis = 0;
+
+ while ( ( ent = gEntList.FindEntityByClassname( ent, "info_player_allies" ) ) != NULL )
+ {
+ if ( IsSpawnPointValid( ent, NULL ) )
+ {
+ m_iSpawnPointCount_Allies++;
+
+ // store in a list
+ m_AlliesSpawnPoints.AddToTail( ent );
+ }
+ else
+ {
+ Warning("Invalid allies spawnpoint at (%.1f,%.1f,%.1f)\n",
+ ent->GetAbsOrigin()[0],ent->GetAbsOrigin()[2],ent->GetAbsOrigin()[2] );
+ }
+ }
+
+ while ( ( ent = gEntList.FindEntityByClassname( ent, "info_player_axis" ) ) != NULL )
+ {
+ if ( IsSpawnPointValid( ent, NULL ) )
+ {
+ m_iSpawnPointCount_Axis++;
+
+ // store in a list
+ m_AxisSpawnPoints.AddToTail( ent );
+ }
+ else
+ {
+ Warning("Invalid axis spawnpoint at (%.1f,%.1f,%.1f)\n",
+ ent->GetAbsOrigin()[0],ent->GetAbsOrigin()[2],ent->GetAbsOrigin()[2] );
+ }
+ }
+
+ m_bLevelInitialized = true;
+ }
+ }
+
+ CUtlVector<EHANDLE> *CDODGameRules::GetSpawnPointListForTeam( int iTeam )
+ {
+ switch ( iTeam )
+ {
+ case TEAM_ALLIES:
+ return &m_AlliesSpawnPoints;
+ case TEAM_AXIS:
+ return &m_AxisSpawnPoints;
+ default:
+ break;
+ }
+
+ return NULL;
+ }
+
+ /* create some proxy entities that we use for transmitting data */
+ void CDODGameRules::CreateStandardEntities()
+ {
+ // Create the player resource
+ g_pPlayerResource = (CPlayerResource*)CBaseEntity::Create( "dod_player_manager", vec3_origin, vec3_angle );
+
+ // Create the objective resource
+ g_pObjectiveResource = (CDODObjectiveResource *)CBaseEntity::Create( "dod_objective_resource", vec3_origin, vec3_angle );
+
+ Assert( g_pObjectiveResource );
+
+ // Create the entity that will send our data to the client.
+#ifdef DBGFLAG_ASSERT
+ CBaseEntity *pEnt =
+#endif
+ CBaseEntity::Create( "dod_gamerules", vec3_origin, vec3_angle );
+ Assert( pEnt );
+ }
+
+ ConVar dod_waverespawnfactor( "dod_waverespawnfactor", "1.0", FCVAR_REPLICATED | FCVAR_CHEAT, "Factor for respawn wave timers" );
+
+ float CDODGameRules::GetWaveTime( int iTeam )
+ {
+ float flRespawnTime = 0.0f;
+
+ switch( iTeam )
+ {
+ case TEAM_ALLIES:
+ flRespawnTime = ( m_iNumAlliesRespawnWaves > 0 ) ? m_AlliesRespawnQueue[m_iAlliesRespawnHead] : -1;
+ break;
+ case TEAM_AXIS:
+ flRespawnTime = ( m_iNumAxisRespawnWaves > 0 ) ? m_AxisRespawnQueue[m_iAxisRespawnHead] : -1;
+ break;
+ default:
+ Assert( !"Why are you trying to get the wave time for a non-team?" );
+ break;
+ }
+
+ return flRespawnTime;
+ }
+
+ float CDODGameRules::GetMaxWaveTime( int nTeam )
+ {
+ float fTime = 0;
+
+ // Quick waves to get everyone in if we are in PREROUND
+ if ( State_Get() == STATE_PREROUND )
+ {
+ return 1.0;
+ }
+
+ int nNumPlayers = GetGlobalDODTeam( nTeam )->GetNumPlayers();
+
+ if( nNumPlayers < 3 )
+ fTime = 6.f;
+ else if( nNumPlayers < 6 )
+ fTime = 8.f;
+ else if( nNumPlayers < 8 )
+ fTime = 10.f;
+ else if( nNumPlayers < 10 )
+ fTime = 11.f;
+ else if( nNumPlayers < 12 )
+ fTime = 12.f;
+ else if( nNumPlayers < 14 )
+ fTime = 13.f;
+ else
+ fTime = 14.f;
+
+ //adjust wave time based on mapper settings
+ //they can adjust the factor ( default 1.0 )
+ // to give longer or shorter wait times for
+ // either team
+ if( nTeam == TEAM_ALLIES )
+ fTime *= m_GamePlayRules.m_fAlliesRespawnFactor;
+ else if( nTeam == TEAM_AXIS )
+ fTime *= m_GamePlayRules.m_fAxisRespawnFactor;
+
+ // Finally, adjust the respawn time based on how well the team is doing
+ // a team with more flags should respawn faster.
+ // Give a bonus to respawn time for each flag that we own that we
+ // don't own by default.
+
+ CControlPointMaster *pMaster = dynamic_cast<CControlPointMaster*>( gEntList.FindEntityByClassname( NULL, "dod_control_point_master" ) );
+
+ if( pMaster )
+ {
+ int advantageFlags = pMaster->CountAdvantageFlags( nTeam );
+
+ // this can be negative if we are losing, this will add time!
+
+ fTime -= (float)(advantageFlags) * dod_flagrespawnbonus.GetFloat();
+ }
+
+ fTime *= dod_waverespawnfactor.GetFloat();
+
+ // Minimum 5 seconds
+ if (fTime <= DEATH_CAM_TIME)
+ fTime = DEATH_CAM_TIME;
+
+ // Maximum 20 seconds
+ if ( fTime > MAX_WAVE_RESPAWN_TIME )
+ {
+ fTime = MAX_WAVE_RESPAWN_TIME;
+ }
+
+ return fTime;
+ }
+
+
+ void CDODGameRules::CreateOrJoinRespawnWave( CDODPlayer *pPlayer )
+ {
+ int team = pPlayer->GetTeamNumber();
+ float flWaveTime = GetWaveTime( team ) - gpGlobals->curtime;
+
+ if( flWaveTime <= 0 )
+ {
+ // start a new wave
+
+ DevMsg( "Wave: Starting a new wave for team %d, time %.1f\n", team, GetMaxWaveTime(team) );
+
+ //start a new wave with this player
+ AddWaveTime( team, GetMaxWaveTime(team) );
+ }
+ else
+ {
+ // see if this player needs to start a new wave
+
+ int team = pPlayer->GetTeamNumber();
+ float flSpawnEligibleTime = gpGlobals->curtime + DEATH_CAM_TIME;
+
+ if ( team == TEAM_ALLIES )
+ {
+ bool bFoundWave = false;
+
+ int i = m_iAlliesRespawnHead;
+
+ while( i != m_iAlliesRespawnTail )
+ {
+ // if the player can fit in this wave, set bFound = true
+ if ( flSpawnEligibleTime < m_AlliesRespawnQueue[i] )
+ {
+ bFoundWave = true;
+ break;
+ }
+
+ i = ( i+1 ) % DOD_RESPAWN_QUEUE_SIZE;
+ }
+
+ if ( !bFoundWave )
+ {
+ // add a new wave to the end
+ AddWaveTime( TEAM_ALLIES, GetMaxWaveTime(TEAM_ALLIES) );
+ }
+ }
+ else if ( team == TEAM_AXIS )
+ {
+ bool bFoundWave = false;
+
+ int i = m_iAxisRespawnHead;
+
+ while( i != m_iAxisRespawnTail )
+ {
+ // if the player can fit in this wave, set bFound = true
+ if ( flSpawnEligibleTime < m_AxisRespawnQueue[i] )
+ {
+ bFoundWave = true;
+ break;
+ }
+
+ i = ( i+1 ) % DOD_RESPAWN_QUEUE_SIZE;
+ }
+
+ if ( !bFoundWave )
+ {
+ // add a new wave to the end
+ AddWaveTime( TEAM_AXIS, GetMaxWaveTime(TEAM_AXIS) );
+ }
+ }
+ else
+ Assert( 0 );
+ }
+ }
+
+ bool CDODGameRules::InRoundRestart( void )
+ {
+ if ( State_Get() == STATE_PREROUND )
+ return true;
+
+ return false;
+ }
+
+ void CDODGameRules::PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info )
+ {
+ CDODPlayer *pDODVictim = ToDODPlayer( pVictim );
+
+ // if you're still playing dod, you know how this works, let's not
+ // interfere with the freezecam panel
+ //bool bPlayed = pDODVictim->HintMessage( HINT_PLAYER_KILLED_WAVETIME );
+
+ // If we already played the killed hint, play the deathcam hint
+ //if ( !bPlayed )
+ //{
+ // pDODVictim->HintMessage( HINT_DEATHCAM );
+ //}
+
+ CBaseEntity *pInflictor = info.GetInflictor();
+ CBaseEntity *pKiller = info.GetAttacker();
+ CDODPlayer *pScorer = ToDODPlayer( GetDeathScorer( pKiller, pInflictor ) );
+
+ if( pScorer && pScorer->IsPlayer() && pScorer != pVictim )
+ {
+ if( pVictim->GetTeamNumber() == pScorer->GetTeamNumber() )
+ {
+ pScorer->HintMessage( HINT_FRIEND_KILLED, true ); //force this
+ }
+ else
+ {
+ pScorer->HintMessage( HINT_ENEMY_KILLED );
+ }
+ }
+
+ // determine if this kill affected a nemesis relationship
+ int iDeathFlags = 0;
+ if ( pScorer )
+ {
+ CalcDominationAndRevenge( pScorer, pDODVictim, &iDeathFlags );
+ }
+
+ pDODVictim->SetDeathFlags( iDeathFlags ); // for deathnotice I assume?
+
+ DeathNotice( pVictim, info );
+
+ // dvsents2: uncomment when removing all FireTargets
+ // variant_t value;
+ // g_EventQueue.AddEvent( "game_playerdie", "Use", value, 0, pVictim, pVictim );
+ FireTargets( "game_playerdie", pVictim, pVictim, USE_TOGGLE, 0 );
+
+ bool bScoring = !IsInWarmup();
+
+ if( bScoring )
+ {
+ pVictim->IncrementDeathCount( 1 );
+ }
+
+ // Did the player kill himself?
+ if ( pVictim == pScorer )
+ {
+ // Players lose a frag for killing themselves
+ //if( bScoring )
+ // pVictim->IncrementFragCount( -1 );
+ }
+ else if ( pScorer )
+ {
+ // if a player dies in a deathmatch game and the killer is a client, award the killer some points
+ if( bScoring )
+ pScorer->IncrementFragCount( DODPointsForKill( pVictim, info ) );
+
+ // Allow the scorer to immediately paint a decal
+ pScorer->AllowImmediateDecalPainting();
+
+ // dvsents2: uncomment when removing all FireTargets
+ //variant_t value;
+ //g_EventQueue.AddEvent( "game_playerkill", "Use", value, 0, pScorer, pScorer );
+ FireTargets( "game_playerkill", pScorer, pScorer, USE_TOGGLE, 0 );
+
+ // see if this saved a capture
+ if ( pDODVictim->m_signals.GetState() & SIGNAL_CAPTUREAREA )
+ {
+ //find the area the player is in and see if his death causes a block
+ CAreaCapture *pArea = dynamic_cast<CAreaCapture *>(gEntList.FindEntityByClassname( NULL, "dod_capture_area" ) );
+ while( pArea )
+ {
+ if ( pArea->CheckIfDeathCausesBlock( pDODVictim, pScorer ) )
+ {
+ break;
+ }
+
+ pArea = dynamic_cast<CAreaCapture *>( gEntList.FindEntityByClassname( pArea, "dod_capture_area" ) );
+ }
+ }
+ if ( pDODVictim->m_bIsDefusing && pDODVictim->m_pDefuseTarget && pScorer->GetTeamNumber() != pDODVictim->GetTeamNumber() )
+ {
+ CDODBombTarget *pTarget = pDODVictim->m_pDefuseTarget;
+
+ pTarget->DefuseBlocked( pScorer );
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_kill_defuser" );
+ if ( event )
+ {
+ event->SetInt( "userid", pScorer->GetUserID() );
+ event->SetInt( "victimid", pDODVictim->GetUserID() );
+
+ gameeventmanager->FireEvent( event );
+ }
+ }
+ }
+ else
+ {
+ // Players lose a frag for letting the world kill them
+ //if( bScoring )
+ // pVictim->IncrementFragCount( -1 );
+ }
+ }
+
+ void CDODGameRules::DetectGameRules( void )
+ {
+ bool bFound = false;
+
+ CBaseEntity *pEnt = NULL;
+
+ pEnt = gEntList.FindEntityByClassname( pEnt, "info_doddetect" );
+
+ while( pEnt )
+ {
+ CDODDetect *pDetect = dynamic_cast<CDODDetect *>(pEnt);
+
+ if( pDetect && pDetect->IsMasteredOn() )
+ {
+ CDODGamePlayRules *pRules = pDetect->GetGamePlay();
+ Assert( pRules );
+ CopyGamePlayLogic( *pRules );
+ bFound = true;
+ break;
+ }
+
+ pEnt = gEntList.FindEntityByClassname( pEnt, "info_doddetect" );
+ }
+
+ if( !bFound )
+ {
+ m_GamePlayRules.Reset();
+ }
+ }
+
+ void CDODGameRules::PlayWinSong( int team )
+ {
+ switch(team)
+ {
+ case TEAM_ALLIES:
+ BroadcastSound( "Game.USWin" );
+ break;
+ case TEAM_AXIS:
+ BroadcastSound( "Game.GermanWin" );
+ break;
+ default:
+ Assert(0);
+ break;
+ }
+ }
+
+ void CDODGameRules::BroadcastSound( const char *sound )
+ {
+ //send it to everyone
+ IGameEvent *event = gameeventmanager->CreateEvent( "dod_broadcast_audio" );
+ if ( event )
+ {
+ event->SetString( "sound", sound );
+ gameeventmanager->FireEvent( event );
+ }
+ }
+
+ void CDODGameRules::PlayStartRoundVoice( void )
+ {
+ // One for the Allies..
+ switch( m_GamePlayRules.m_iAlliesStartRoundVoice )
+ {
+ case STARTROUND_ATTACK:
+ PlaySpawnSoundToTeam( "Voice.US_ObjectivesAttack", TEAM_ALLIES );
+ break;
+
+ case STARTROUND_DEFEND:
+ PlaySpawnSoundToTeam( "Voice.US_ObjectivesDefend", TEAM_ALLIES );
+ break;
+
+ case STARTROUND_BEACH:
+ PlaySpawnSoundToTeam( "Voice.US_Beach", TEAM_ALLIES );
+ break;
+
+ case STARTROUND_ATTACK_TIMED:
+ PlaySpawnSoundToTeam( "Voice.US_ObjectivesAttackTimed", TEAM_ALLIES );
+ break;
+
+ case STARTROUND_DEFEND_TIMED:
+ PlaySpawnSoundToTeam( "Voice.US_ObjectivesDefendTimed", TEAM_ALLIES );
+ break;
+
+ case STARTROUND_FLAGS:
+ default:
+ PlaySpawnSoundToTeam( "Voice.US_Flags", TEAM_ALLIES );
+ break;
+ }
+
+ // and one for the Axis
+ switch( m_GamePlayRules.m_iAxisStartRoundVoice )
+ {
+ case STARTROUND_ATTACK:
+ PlaySpawnSoundToTeam( "Voice.German_ObjectivesAttack", TEAM_AXIS );
+ break;
+
+ case STARTROUND_DEFEND:
+ PlaySpawnSoundToTeam( "Voice.German_ObjectivesDefend", TEAM_AXIS );
+ break;
+
+ case STARTROUND_BEACH:
+ PlaySpawnSoundToTeam( "Voice.German_Beach", TEAM_AXIS );
+ break;
+
+ case STARTROUND_ATTACK_TIMED:
+ PlaySpawnSoundToTeam( "Voice.German_ObjectivesAttackTimed", TEAM_AXIS );
+ break;
+
+ case STARTROUND_DEFEND_TIMED:
+ PlaySpawnSoundToTeam( "Voice.German_ObjectivesDefendTimed", TEAM_AXIS );
+ break;
+
+ case STARTROUND_FLAGS:
+ default:
+ PlaySpawnSoundToTeam( "Voice.German_Flags", TEAM_AXIS );
+ break;
+ }
+ }
+
+ void CDODGameRules::PlaySpawnSoundToTeam( const char *sound, int team )
+ {
+ // find the first valid player and make them do it as a voice command
+ CDODPlayer *pPlayer;
+
+ static int iLastSpeaker = 1;
+
+ int iCurrent = iLastSpeaker;
+
+ bool bBreakLoop = false;
+
+ while( !bBreakLoop )
+ {
+ iCurrent++;
+ if( iCurrent > gpGlobals->maxClients )
+ iCurrent = 1;
+
+ if( iCurrent == iLastSpeaker )
+ {
+ // couldn't find a different player. check the same player again
+ // and then break regardless
+ bBreakLoop = true;
+ }
+
+ pPlayer = ToDODPlayer( UTIL_PlayerByIndex( iCurrent ) );
+
+ if (pPlayer == NULL)
+ continue;
+
+ if (FNullEnt( pPlayer->edict() ))
+ continue;
+
+ if( pPlayer && pPlayer->GetTeamNumber() == team && pPlayer->IsAlive() )
+ {
+ CPASFilter filter( pPlayer->WorldSpaceCenter() );
+ pPlayer->EmitSound( filter, pPlayer->entindex(), sound );
+
+ pPlayer->DoAnimationEvent( PLAYERANIMEVENT_HANDSIGNAL );
+
+ iLastSpeaker = iCurrent;
+ break;
+ }
+ }
+ }
+
+ void CDODGameRules::ClientDisconnected( edict_t *pClient )
+ {
+ CDODPlayer *pPlayer = ToDODPlayer( GetContainingEntity( pClient ) );
+
+ if( pPlayer )
+ {
+ pPlayer->DestroyRagdoll();
+
+ pPlayer->StatEvent_UploadStats();
+ }
+
+ // Tally the latest time for this player
+ pPlayer->TallyLatestTimePlayedPerClass( pPlayer->GetTeamNumber(), pPlayer->m_Shared.DesiredPlayerClass() );
+
+ pPlayer->RemoveNemesisRelationships();
+
+ for( int j=0;j<7;j++ )
+ {
+ m_flSecondsPlayedPerClass_Allies[j] += pPlayer->m_flTimePlayedPerClass_Allies[j];
+ m_flSecondsPlayedPerClass_Axis[j] += pPlayer->m_flTimePlayedPerClass_Axis[j];
+ }
+
+ int iPlayerIndex = pPlayer->entindex();
+ Assert( iPlayerIndex >= 1 && iPlayerIndex <= MAX_PLAYERS);
+ if ( iPlayerIndex >= 1 && iPlayerIndex <= MAX_PLAYERS )
+ {
+ // for every other player, set all all the kills with respect to this player to 0
+ for ( int i = 1; i <= MAX_PLAYERS; i++ )
+ {
+ CDODPlayer *p = ToDODPlayer( UTIL_PlayerByIndex(i) );
+ if ( !p )
+ continue;
+
+ p->iNumKilledByUnanswered[iPlayerIndex] = 0;
+ }
+ }
+
+ BaseClass::ClientDisconnected( pClient );
+ }
+
+ void CDODGameRules::DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info )
+ {
+ // Work out what killed the player, and send a message to all clients about it
+ const char *killer_weapon_name = "world"; // by default, the player is killed by the world
+ int killer_ID = 0;
+
+ // Find the killer & the scorer
+ CBaseEntity *pInflictor = info.GetInflictor();
+ CBaseEntity *pKiller = info.GetAttacker();
+ CDODPlayer *pScorer = ToDODPlayer( GetDeathScorer( pKiller, pInflictor ) );
+ CDODPlayer *pDODVictim = ToDODPlayer( pVictim );
+
+ Assert( pDODVictim );
+
+ if ( pScorer ) // Is the killer a client?
+ {
+ killer_ID = pScorer->GetUserID();
+
+ if ( pInflictor )
+ {
+ if ( pInflictor == pScorer )
+ {
+ CWeaponDODBase *pWeapon = pScorer->GetActiveDODWeapon();
+
+ if ( pWeapon )
+ {
+ int iWeaponType = pWeapon->GetDODWpnData().m_WeaponType;
+
+ // Putting this here because we already have the weapon pointer.
+ if ( iWeaponType == WPN_TYPE_MG && pScorer->GetTeamNumber() != pVictim->GetTeamNumber() )
+ {
+ CDODBipodWeapon *pMG = dynamic_cast<CDODBipodWeapon *>( pWeapon );
+ Assert( pMG );
+ if ( pMG->IsDeployed() )
+ {
+ pScorer->HandleDeployedMGKillCount( 1 );
+ }
+ }
+
+ // if the weapon does not belong to the same team
+ if ( pWeapon->GetDODWpnData().m_iDefaultTeam != pScorer->GetTeamNumber() &&
+ pScorer->GetTeamNumber() != pVictim->GetTeamNumber() )
+ {
+ pScorer->HandleEnemyWeaponsAchievement( 1 );
+ }
+
+ // achievement for getting kills with several different weapon types in one life
+ if ( pScorer->GetTeamNumber() != pVictim->GetTeamNumber() )
+ {
+ pScorer->HandleComboWeaponKill( iWeaponType );
+ }
+
+ if( info.GetDamageCustom() & MELEE_DMG_SECONDARYATTACK )
+ {
+ //it was a butt or bayonet!
+ killer_weapon_name = pWeapon->GetSecondaryDeathNoticeName();
+ }
+ // If the inflictor is the killer, then it must be their current weapon doing the damage
+ else
+ {
+ killer_weapon_name = pWeapon->GetClassname();
+ }
+ }
+ }
+ else
+ {
+ killer_weapon_name = STRING( pInflictor->m_iClassname ); // it's just that easy
+ }
+ }
+ }
+ else
+ {
+ killer_weapon_name = STRING( pInflictor->m_iClassname );
+ }
+
+ // strip the NPC_* or weapon_* from the inflictor's classname
+ if ( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 )
+ {
+ killer_weapon_name += 7;
+ }
+ else if ( strncmp( killer_weapon_name, "func_", 5 ) == 0 )
+ {
+ killer_weapon_name += 5;
+ }
+ else if ( strncmp( killer_weapon_name, "rocket_", 7 ) == 0 )
+ {
+ killer_weapon_name += 7;
+ }
+ else if ( strncmp( killer_weapon_name, "grenade_", 8 ) == 0 )
+ {
+ killer_weapon_name += 8;
+
+ // achievement for getting kills with several different weapon types in one life
+ if ( pScorer && pScorer->GetTeamNumber() != pVictim->GetTeamNumber() )
+ {
+ pScorer->HandleComboWeaponKill( WPN_TYPE_GRENADE );
+ }
+ }
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "player_death" );
+
+ if ( event )
+ {
+ event->SetInt("userid", pVictim->GetUserID() );
+ event->SetInt("attacker", killer_ID );
+ event->SetString("weapon", killer_weapon_name );
+ event->SetInt("priority", 7 );
+
+ if ( pDODVictim->GetDeathFlags() & DOD_DEATHFLAG_DOMINATION )
+ {
+ event->SetInt( "dominated", 1 );
+ }
+ if ( pDODVictim->GetDeathFlags() & DOD_DEATHFLAG_REVENGE )
+ {
+ event->SetInt( "revenge", 1 );
+ }
+
+ gameeventmanager->FireEvent( event );
+ }
+ }
+
+
+ // CDODDetect - map entity for mappers to choose game rules
+ LINK_ENTITY_TO_CLASS( info_doddetect, CDODDetect );
+
+ CDODDetect::CDODDetect()
+ {
+ m_GamePlayRules.Reset();
+ }
+
+ void CDODDetect::Spawn( void )
+ {
+ SetSolid( SOLID_NONE );
+
+ BaseClass::Spawn();
+ }
+
+ bool CDODDetect::IsMasteredOn( void )
+ {
+ //For now return true
+ return true;
+ }
+
+ bool CDODDetect::KeyValue( const char *szKeyName, const char *szValue )
+ {
+ if (FStrEq(szKeyName, "detect_allies_respawnfactor"))
+ {
+ m_GamePlayRules.m_fAlliesRespawnFactor = atof(szValue);
+ }
+ else if (FStrEq(szKeyName, "detect_axis_respawnfactor"))
+ {
+ m_GamePlayRules.m_fAxisRespawnFactor = atof(szValue);
+ }
+ else if (FStrEq(szKeyName, "detect_allies_startroundvoice"))
+ {
+ m_GamePlayRules.m_iAlliesStartRoundVoice = atoi(szValue);
+ }
+ else if (FStrEq(szKeyName, "detect_axis_startroundvoice"))
+ {
+ m_GamePlayRules.m_iAxisStartRoundVoice = atof(szValue);
+ }
+ else
+ return CBaseEntity::KeyValue( szKeyName, szValue );
+
+ return true;
+ }
+
+ //checks to see if the desired team is stacked, returns true if it is
+ bool CDODGameRules::TeamStacked( int iNewTeam, int iCurTeam )
+ {
+ //players are allowed to change to their own team
+ if(iNewTeam == iCurTeam)
+ return false;
+
+ int iTeamLimit = mp_limitteams.GetInt();
+
+ // Tabulate the number of players on each team.
+ int iNumAllies = GetGlobalTeam( TEAM_ALLIES )->GetNumPlayers();
+ int iNumAxis = GetGlobalTeam( TEAM_AXIS )->GetNumPlayers();
+
+ switch ( iNewTeam )
+ {
+ case TEAM_ALLIES:
+ if( iCurTeam != TEAM_UNASSIGNED && iCurTeam != TEAM_SPECTATOR )
+ {
+ if((iNumAllies + 1) > (iNumAxis + iTeamLimit - 1))
+ return true;
+ else
+ return false;
+ }
+ else
+ {
+ if((iNumAllies + 1) > (iNumAxis + iTeamLimit))
+ return true;
+ else
+ return false;
+ }
+ break;
+ case TEAM_AXIS:
+ if( iCurTeam != TEAM_UNASSIGNED && iCurTeam != TEAM_SPECTATOR )
+ {
+ if((iNumAxis + 1) > (iNumAllies + iTeamLimit - 1))
+ return true;
+ else
+ return false;
+ }
+ else
+ {
+ if((iNumAxis + 1) > (iNumAllies + iTeamLimit))
+ return true;
+ else
+ return false;
+ }
+ break;
+ }
+
+ return false;
+ }
+
+ // Falling damage stuff.
+ #define DOD_PLAYER_FATAL_FALL_SPEED 900 // approx 60 feet
+ #define DOD_PLAYER_MAX_SAFE_FALL_SPEED 500 // approx 20 feet
+ #define DOD_DAMAGE_FOR_FALL_SPEED ((float)100 / ( DOD_PLAYER_FATAL_FALL_SPEED - DOD_PLAYER_MAX_SAFE_FALL_SPEED )) // damage per unit per second.
+
+ /*
+ #define PLAYER_FALL_PUNCH_THRESHHOLD (float)350 // won't punch player's screen/make scrape noise unless player falling at least this fast.
+ */
+
+ float CDODGameRules::FlPlayerFallDamage( CBasePlayer *pPlayer )
+ {
+ pPlayer->m_Local.m_flFallVelocity -= DOD_PLAYER_MAX_SAFE_FALL_SPEED;
+ return pPlayer->m_Local.m_flFallVelocity * DOD_DAMAGE_FOR_FALL_SPEED;
+ }
+
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Init CS ammo definitions
+//-----------------------------------------------------------------------------
+
+// shared ammo definition
+// JAY: Trying to make a more physical bullet response
+#define BULLET_MASS_GRAINS_TO_LB(grains) (0.002285*(grains)/16.0f)
+#define BULLET_MASS_GRAINS_TO_KG(grains) lbs2kg(BULLET_MASS_GRAINS_TO_LB(grains))
+
+// exaggerate all of the forces, but use real numbers to keep them consistent
+#define BULLET_IMPULSE_EXAGGERATION 1
+
+// convert a velocity in ft/sec and a mass in grains to an impulse in kg in/s
+#define BULLET_IMPULSE(grains, ftpersec) ((ftpersec)*12*BULLET_MASS_GRAINS_TO_KG(grains)*BULLET_IMPULSE_EXAGGERATION)
+
+CAmmoDef* GetAmmoDef()
+{
+ static CAmmoDef def;
+ static bool bInitted = false;
+
+ if ( !bInitted )
+ {
+ bInitted = true;
+
+ //pistol ammo
+ def.AddAmmoType( DOD_AMMO_COLT, DMG_BULLET, TRACER_NONE, 0, 0, 21, 5000, 10, 14 );
+ def.AddAmmoType( DOD_AMMO_P38, DMG_BULLET, TRACER_NONE, 0, 0, 24, 5000, 10, 14 );
+ def.AddAmmoType( DOD_AMMO_C96, DMG_BULLET, TRACER_NONE, 0, 0, 60, 5000, 10, 14 );
+
+ //rifles
+ def.AddAmmoType( DOD_AMMO_GARAND, DMG_BULLET, TRACER_NONE, 0, 0, 88, 9000, 10, 14 );
+ def.AddAmmoType( DOD_AMMO_K98, DMG_BULLET, TRACER_NONE, 0, 0, 65, 9000, 10, 14 );
+ def.AddAmmoType( DOD_AMMO_M1CARBINE, DMG_BULLET, TRACER_NONE, 0, 0, 165, 9000, 10, 14 );
+ def.AddAmmoType( DOD_AMMO_SPRING, DMG_BULLET, TRACER_NONE, 0, 0, 55, 9000, 10, 14 );
+
+ //submg
+ def.AddAmmoType( DOD_AMMO_SUBMG, DMG_BULLET, TRACER_NONE, 0, 0, 210, 7000, 10, 14 );
+ def.AddAmmoType( DOD_AMMO_BAR, DMG_BULLET, TRACER_LINE_AND_WHIZ, 0, 0, 260, 9000, 10, 14 );
+
+ //mg
+ def.AddAmmoType( DOD_AMMO_30CAL, DMG_BULLET | DMG_MACHINEGUN, TRACER_LINE_AND_WHIZ, 0, 0, 300, 9000, 10, 14 );
+ def.AddAmmoType( DOD_AMMO_MG42, DMG_BULLET | DMG_MACHINEGUN, TRACER_LINE_AND_WHIZ, 0, 0, 500, 9000, 10, 14 );
+
+ //rockets
+ def.AddAmmoType( DOD_AMMO_ROCKET, DMG_BLAST, TRACER_NONE, 0, 0, 5, 9000, 10, 14 );
+
+ //grenades
+ def.AddAmmoType( DOD_AMMO_HANDGRENADE, DMG_BLAST, TRACER_NONE, 0, 0, 2, 1, 4, 8 );
+ def.AddAmmoType( DOD_AMMO_STICKGRENADE, DMG_BLAST, TRACER_NONE, 0, 0, 2, 1, 4, 8 );
+ def.AddAmmoType( DOD_AMMO_HANDGRENADE_EX, DMG_BLAST, TRACER_NONE, 0, 0, 1, 1, 4, 8 );
+ def.AddAmmoType( DOD_AMMO_STICKGRENADE_EX, DMG_BLAST, TRACER_NONE, 0, 0, 1, 1, 4, 8 );
+
+ // smoke grenades
+ def.AddAmmoType( DOD_AMMO_SMOKEGRENADE_US, DMG_BLAST, TRACER_NONE, 0, 0, 2, 1, 4, 8 );
+ def.AddAmmoType( DOD_AMMO_SMOKEGRENADE_GER, DMG_BLAST, TRACER_NONE, 0, 0, 2, 1, 4, 8 );
+ def.AddAmmoType( DOD_AMMO_SMOKEGRENADE_US_LIVE, DMG_BLAST, TRACER_NONE, 0, 0, 2, 1, 4, 8 );
+ def.AddAmmoType( DOD_AMMO_SMOKEGRENADE_GER_LIVE,DMG_BLAST, TRACER_NONE, 0, 0, 2, 1, 4, 8 );
+
+ // rifle grenades
+ def.AddAmmoType( DOD_AMMO_RIFLEGRENADE_US, DMG_BLAST, TRACER_NONE, 0, 0, 2, 1, 4, 8 );
+ def.AddAmmoType( DOD_AMMO_RIFLEGRENADE_GER, DMG_BLAST, TRACER_NONE, 0, 0, 2, 1, 4, 8 );
+ def.AddAmmoType( DOD_AMMO_RIFLEGRENADE_US_LIVE, DMG_BLAST, TRACER_NONE, 0, 0, 2, 1, 4, 8 );
+ def.AddAmmoType( DOD_AMMO_RIFLEGRENADE_GER_LIVE,DMG_BLAST, TRACER_NONE, 0, 0, 2, 1, 4, 8 );
+ }
+
+ return &def;
+}
+
+#ifndef CLIENT_DLL
+void CDODGameRules::AddWaveTime( int team, float flTime )
+{
+ switch ( team )
+ {
+ case TEAM_ALLIES:
+ {
+ Assert( m_iNumAlliesRespawnWaves < DOD_RESPAWN_QUEUE_SIZE );
+
+ if ( m_iNumAlliesRespawnWaves >= DOD_RESPAWN_QUEUE_SIZE )
+ {
+ Warning( "Trying to add too many allies respawn waves\n" );
+ return;
+ }
+
+ m_AlliesRespawnQueue.Set( m_iAlliesRespawnTail, gpGlobals->curtime + flTime );
+ m_iNumAlliesRespawnWaves++;
+
+ m_iAlliesRespawnTail = ( m_iAlliesRespawnTail + 1 ) % DOD_RESPAWN_QUEUE_SIZE;
+
+ DevMsg( 1, "AddWaveTime ALLIES head %d tail %d numtotal %d time %.1f\n",
+ m_iAlliesRespawnHead.Get(),
+ m_iAlliesRespawnTail.Get(),
+ m_iNumAlliesRespawnWaves,
+ gpGlobals->curtime + flTime );
+ }
+ break;
+ case TEAM_AXIS:
+ {
+ Assert( m_iNumAxisRespawnWaves < DOD_RESPAWN_QUEUE_SIZE );
+
+ if ( m_iNumAxisRespawnWaves >= DOD_RESPAWN_QUEUE_SIZE )
+ {
+ Warning( "Trying to add too many axis respawn waves\n" );
+ return;
+ }
+
+ m_AxisRespawnQueue.Set( m_iAxisRespawnTail, gpGlobals->curtime + flTime );
+ m_iNumAxisRespawnWaves++;
+
+ m_iAxisRespawnTail = ( m_iAxisRespawnTail + 1 ) % DOD_RESPAWN_QUEUE_SIZE;
+
+ DevMsg( 1, "AddWaveTime AXIS head %d tail %d numtotal %d time %.1f\n",
+ m_iAxisRespawnHead.Get(),
+ m_iAxisRespawnTail.Get(),
+ m_iNumAxisRespawnWaves,
+ gpGlobals->curtime + flTime );
+ }
+ break;
+ default:
+ Assert(0);
+ break;
+ }
+}
+
+void CDODGameRules::PopWaveTime( int team )
+{
+ switch ( team )
+ {
+ case TEAM_ALLIES:
+ {
+ Assert( m_iNumAlliesRespawnWaves > 0 );
+
+ m_iAlliesRespawnHead = ( m_iAlliesRespawnHead + 1 ) % DOD_RESPAWN_QUEUE_SIZE;
+ m_iNumAlliesRespawnWaves--;
+
+ DevMsg( 1, "PopWaveTime ALLIES head %d tail %d numtotal %d time %.1f\n",
+ m_iAlliesRespawnHead.Get(),
+ m_iAlliesRespawnTail.Get(),
+ m_iNumAlliesRespawnWaves,
+ gpGlobals->curtime );
+ }
+ break;
+ case TEAM_AXIS:
+ {
+ Assert( m_iNumAxisRespawnWaves > 0 );
+
+ m_iAxisRespawnHead = ( m_iAxisRespawnHead + 1 ) % DOD_RESPAWN_QUEUE_SIZE;
+ m_iNumAxisRespawnWaves--;
+
+ DevMsg( 1, "PopWaveTime AXIS head %d tail %d numtotal %d time %.1f\n",
+ m_iAxisRespawnHead.Get(),
+ m_iAxisRespawnTail.Get(),
+ m_iNumAxisRespawnWaves,
+ gpGlobals->curtime );
+ }
+ break;
+ default:
+ Assert(0);
+ break;
+ }
+}
+
+#endif
+
+
+#ifndef CLIENT_DLL
+
+const char *CDODGameRules::GetChatPrefix( bool bTeamOnly, CBasePlayer *pPlayer )
+{
+ char *pszPrefix = "";
+
+ if ( !pPlayer ) // dedicated server output
+ {
+ pszPrefix = "";
+ }
+ else
+ {
+ // don't show dead prefix if in the bonus round or at round end
+ // because we can chat at these times.
+ bool bShowDeadPrefix = ( pPlayer->IsAlive() == false ) && !IsInBonusRound() &&
+ ( State_Get() != STATE_GAME_OVER );
+
+ if ( pPlayer->GetTeamNumber() == TEAM_SPECTATOR )
+ {
+ return "";
+ }
+
+ if ( bTeamOnly )
+ {
+ if ( bShowDeadPrefix )
+ {
+ pszPrefix = "(Dead)(Team)"; //#chatprefix_deadteam";
+ }
+ else
+ {
+ //MATTTODO: localize chat prefixes
+ pszPrefix = "(Team)"; //"#chatprefix_team";
+ }
+ }
+ // everyone
+ else
+ {
+ if ( bShowDeadPrefix )
+ {
+ pszPrefix = "(Dead)"; //"#chatprefix_dead";
+ }
+ }
+ }
+
+ return pszPrefix;
+}
+
+void CDODGameRules::ClientSettingsChanged( CBasePlayer *pPlayer )
+{
+ CDODPlayer *pDODPlayer = ToDODPlayer( pPlayer );
+
+ Assert( pDODPlayer );
+
+ pDODPlayer->SetAutoReload( Q_atoi( engine->GetClientConVarValue( pPlayer->entindex(), "cl_autoreload" ) ) > 0 );
+ pDODPlayer->SetShowHints( Q_atoi( engine->GetClientConVarValue( pPlayer->entindex(), "cl_showhelp" ) ) > 0 );
+ pDODPlayer->SetAutoRezoom( Q_atoi( engine->GetClientConVarValue( pPlayer->entindex(), "cl_autorezoom" ) ) > 0 );
+
+ BaseClass::ClientSettingsChanged( pPlayer );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Determines if attacker and victim have gotten domination or revenge
+//-----------------------------------------------------------------------------
+void CDODGameRules::CalcDominationAndRevenge( CDODPlayer *pAttacker, CDODPlayer *pVictim, int *piDeathFlags )
+{
+ // team kills don't count
+ if ( pAttacker->GetTeamNumber() == pVictim->GetTeamNumber() )
+ return;
+
+ int iKillsUnanswered = ++(pVictim->iNumKilledByUnanswered[pAttacker->entindex()]);
+
+ pAttacker->iNumKilledByUnanswered[pVictim->entindex()] = 0;
+
+ if ( DOD_KILLS_DOMINATION == iKillsUnanswered )
+ {
+ // this is the Nth unanswered kill between killer and victim, killer is now dominating victim
+ *piDeathFlags |= DOD_DEATHFLAG_DOMINATION;
+
+ // set victim to be dominated by killer
+ pAttacker->m_Shared.SetPlayerDominated( pVictim, true );
+
+ pAttacker->StatEvent_ScoredDomination();
+ }
+ else if ( pVictim->m_Shared.IsPlayerDominated( pAttacker->entindex() ) )
+ {
+ // the killer killed someone who was dominating him, gains revenge
+ *piDeathFlags |= DOD_DEATHFLAG_REVENGE;
+
+ // set victim to no longer be dominating the killer
+ pVictim->m_Shared.SetPlayerDominated( pAttacker, false );
+
+ pAttacker->StatEvent_ScoredRevenge();
+ }
+}
+
+int CDODGameRules::DODPointsForKill( CBasePlayer *pVictim, const CTakeDamageInfo &info )
+{
+ if ( IsInWarmup() )
+ return 0;
+
+ CBaseEntity *pInflictor = info.GetInflictor();
+ CBaseEntity *pKiller = info.GetAttacker();
+ CDODPlayer *pScorer = ToDODPlayer( GetDeathScorer( pKiller, pInflictor ) );
+
+ // Don't give -1 points for killing a teammate with the bomb.
+ // It was their fault for standing too close really.
+ if ( pVictim->GetTeamNumber() == pScorer->GetTeamNumber() &&
+ info.GetDamageType() & DMG_BOMB )
+ {
+ return 0;
+ }
+
+ return BaseClass::IPointsForKill( pScorer, pVictim );
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the weapon in the player's inventory that would be better than
+// the given weapon.
+// Note, this version allows us to switch to a weapon that has no ammo as a last
+// resort.
+//-----------------------------------------------------------------------------
+CBaseCombatWeapon *CDODGameRules::GetNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon )
+{
+ CBaseCombatWeapon *pCheck;
+ CBaseCombatWeapon *pBest;// this will be used in the event that we don't find a weapon in the same category.
+
+ int iCurrentWeight = -1;
+ int iBestWeight = -1;// no weapon lower than -1 can be autoswitched to
+ pBest = NULL;
+
+ // If I have a weapon, make sure I'm allowed to holster it
+ if ( pCurrentWeapon )
+ {
+ if ( !pCurrentWeapon->AllowsAutoSwitchFrom() || !pCurrentWeapon->CanHolster() )
+ {
+ // Either this weapon doesn't allow autoswitching away from it or I
+ // can't put this weapon away right now, so I can't switch.
+ return NULL;
+ }
+
+ iCurrentWeight = pCurrentWeapon->GetWeight();
+ }
+
+ for ( int i = 0 ; i < pPlayer->WeaponCount(); ++i )
+ {
+ pCheck = pPlayer->GetWeapon( i );
+ if ( !pCheck )
+ continue;
+
+ // If we have an active weapon and this weapon doesn't allow autoswitching away
+ // from another weapon, skip it.
+ if ( pCurrentWeapon && !pCheck->AllowsAutoSwitchTo() )
+ continue;
+
+ int iWeight = pCheck->GetWeight();
+
+ // Empty weapons are lowest priority
+ if ( !pCheck->HasAnyAmmo() )
+ {
+ iWeight = 0;
+ }
+
+ if ( iWeight > -1 && iWeight == iCurrentWeight && pCheck != pCurrentWeapon )
+ {
+ // this weapon is from the same category.
+ if ( pPlayer->Weapon_CanSwitchTo( pCheck ) )
+ {
+ return pCheck;
+ }
+ }
+ else if ( iWeight > iBestWeight && pCheck != pCurrentWeapon )// don't reselect the weapon we're trying to get rid of
+ {
+ //Msg( "Considering %s\n", STRING( pCheck->GetClassname() );
+ // we keep updating the 'best' weapon just in case we can't find a weapon of the same weight
+ // that the player was using. This will end up leaving the player with his heaviest-weighted
+ // weapon.
+
+ // if this weapon is useable, flag it as the best
+ iBestWeight = pCheck->GetWeight();
+ pBest = pCheck;
+ }
+ }
+
+ // if we make it here, we've checked all the weapons and found no useable
+ // weapon in the same catagory as the current weapon.
+
+ // if pBest is null, we didn't find ANYTHING. Shouldn't be possible- should always
+ // at least get the crowbar, but ya never know.
+ return pBest;
+}
+
+char *szHitgroupNames[] =
+{
+ "generic",
+ "head",
+ "chest",
+ "stomach",
+ "arm_left",
+ "arm_right",
+ "leg_left",
+ "leg_right"
+};
+
+void CDODGameRules::WriteStatsFile( const char *pszLogName )
+{
+ int i, j, k;
+
+ FileHandle_t hFile = filesystem->Open( pszLogName, "w" );
+ if ( hFile == FILESYSTEM_INVALID_HANDLE )
+ {
+ Warning( "Helper_LoadFile: missing %s\n", pszLogName );
+ return;
+ }
+
+ // Header
+ filesystem->FPrintf( hFile, "<?xml version=\"1.0\" ?>\n\n" );
+
+ // open stats
+ filesystem->FPrintf( hFile, "<stats>\n" );
+
+ // per player
+ for ( i=0;i<MAX_PLAYERS;i++ )
+ {
+ CDODPlayer *pPlayer = ToDODPlayer( UTIL_PlayerByIndex( i ) );
+
+ if ( pPlayer )
+ {
+ filesystem->FPrintf( hFile, "\t<player>\n" );
+
+ filesystem->FPrintf( hFile, "\t\t<playername>%s</playername>", pPlayer->GetPlayerName() );
+ filesystem->FPrintf( hFile, "\t\t<steamid>STEAM:0:01</steamid>" );
+
+ //float flTimePlayed = gpGlobals->curtime - pPlayer->m_flConnectTime;
+ //filesystem->FPrintf( hFile, "\t\t<time_played>%.1f</time_played>\n", flTimePlayed );
+
+ /*
+ pPlayer->TallyLatestTimePlayedPerClass( pPlayer->GetTeamNumber(), pPlayer->m_Shared.DesiredPlayerClass() );
+
+ filesystem->FPrintf( hFile, "\t\t<time_played_per_class>\n" );
+ for( j=0;j<7;j++ )
+ {
+ // TODO : add real class names
+ filesystem->FPrintf( hFile, "\t\t\t<class%i>%.1f</class%i>\n",
+ j,
+ pPlayer->m_flTimePlayedPerClass[j],
+ j );
+ }
+ filesystem->FPrintf( hFile, "\t\t</time_played_per_class>\n" );
+ */
+
+ filesystem->FPrintf( hFile, "\t\t<area_captures>%i</area_captures>\n", pPlayer->m_iNumAreaCaptures );
+ filesystem->FPrintf( hFile, "\t\t<area_defenses>%i</area_defenses>\n", pPlayer->m_iNumAreaDefenses );
+ filesystem->FPrintf( hFile, "\t\t<bonus_round_kills>%i</bonus_round_kills>\n", pPlayer->m_iNumBonusRoundKills );
+
+ for ( j=0;j<MAX_WEAPONS;j++ )
+ {
+ if ( pPlayer->m_WeaponStats[j].m_iNumShotsTaken > 0 )
+ {
+ filesystem->FPrintf( hFile, "\t\t<weapon>\n" );
+
+ // weapon id
+ // weapon name
+
+ filesystem->FPrintf( hFile, "\t\t\t<weaponname>%s</weaponname>\n", WeaponIDToAlias( j ) );
+ filesystem->FPrintf( hFile, "\t\t\t<weaponid>%i</weaponid>\n", j );
+ filesystem->FPrintf( hFile, "\t\t\t<shots>%i</shots>\n", pPlayer->m_WeaponStats[j].m_iNumShotsTaken );
+ filesystem->FPrintf( hFile, "\t\t\t<hits>%i</hits>\n", pPlayer->m_WeaponStats[j].m_iNumShotsHit );
+ filesystem->FPrintf( hFile, "\t\t\t<damage>%i</damage>\n", pPlayer->m_WeaponStats[j].m_iTotalDamageGiven );
+ filesystem->FPrintf( hFile, "\t\t\t<avgdist>%.1f</avgdist>\n", pPlayer->m_WeaponStats[j].m_flAverageHitDistance );
+ filesystem->FPrintf( hFile, "\t\t\t<kills>%i</kills>\n", pPlayer->m_WeaponStats[j].m_iNumKills );
+
+ filesystem->FPrintf( hFile, "\t\t\t<hitgroups_hit>\n" );
+ for( k=0;k<8;k++ )
+ {
+ if ( pPlayer->m_WeaponStats[j].m_iBodygroupsHit[k] > 0 )
+ {
+ filesystem->FPrintf( hFile, "\t\t\t\t<%s>%i</%s>\n",
+ szHitgroupNames[k],
+ pPlayer->m_WeaponStats[j].m_iBodygroupsHit[k],
+ szHitgroupNames[k] );
+ }
+ }
+ filesystem->FPrintf( hFile, "\t\t\t</hitgroups_hit>\n" );
+
+ filesystem->FPrintf( hFile, "\t\t\t<times_hit>%i</times_hit>\n", pPlayer->m_WeaponStats[j].m_iNumHitsTaken );
+ filesystem->FPrintf( hFile, "\t\t\t<damage_taken>%i</damage_taken>\n", pPlayer->m_WeaponStats[j].m_iTotalDamageTaken );
+ filesystem->FPrintf( hFile, "\t\t\t<times_killed>%i</times_killed>\n", pPlayer->m_WeaponStats[j].m_iTimesKilled );
+
+ filesystem->FPrintf( hFile, "\t\t\t<hit_in_hitgroups>\n" );
+ for( k=0;k<8;k++ )
+ {
+ if ( pPlayer->m_WeaponStats[j].m_iHitInBodygroups[k] > 0 )
+ {
+ filesystem->FPrintf( hFile, "\t\t\t\t<%s>%i</%s>\n",
+ szHitgroupNames[k],
+ pPlayer->m_WeaponStats[j].m_iHitInBodygroups[k],
+ szHitgroupNames[k] );
+ }
+ }
+
+ filesystem->FPrintf( hFile, "\t\t\t</hit_in_hitgroups>\n" );
+
+ filesystem->FPrintf( hFile, "\t\t</weapon>\n" );
+ }
+ }
+
+ int numKilled = pPlayer->m_KilledPlayers.Count();
+ for ( j=0;j<numKilled;j++ )
+ {
+ filesystem->FPrintf( hFile, "<victim>\n" );
+ filesystem->FPrintf( hFile, "\t<name>%s</name>\n", pPlayer->m_KilledPlayers[j].m_szPlayerName );
+ filesystem->FPrintf( hFile, "\t<userid>%i</userid>\n", pPlayer->m_KilledPlayers[j].m_iUserID );
+ filesystem->FPrintf( hFile, "\t<kills>%i</kills>\n", pPlayer->m_KilledPlayers[j].m_iKills );
+ filesystem->FPrintf( hFile, "\t<damage>%i</damage>\n", pPlayer->m_KilledPlayers[j].m_iTotalDamage );
+ filesystem->FPrintf( hFile, "</victim>" );
+ }
+
+ int numAttackers = pPlayer->m_KilledByPlayers.Count();
+ for ( j=0;j<numAttackers;j++ )
+ {
+ filesystem->FPrintf( hFile, "<attacker>" );
+ filesystem->FPrintf( hFile, "\t<name>%s</name>\n", pPlayer->m_KilledByPlayers[j].m_szPlayerName );
+ filesystem->FPrintf( hFile, "\t<userid>%i</userid>\n", pPlayer->m_KilledByPlayers[j].m_iUserID );
+ filesystem->FPrintf( hFile, "\t<kills>%i</kills>\n", pPlayer->m_KilledByPlayers[j].m_iKills );
+ filesystem->FPrintf( hFile, "\t<damage>%i</damage>\n", pPlayer->m_KilledByPlayers[j].m_iTotalDamage );
+ filesystem->FPrintf( hFile, "</attacker>" );
+ }
+
+ filesystem->FPrintf( hFile, "\t</player>\n" );
+ }
+ }
+
+ // close stats
+ filesystem->FPrintf( hFile, "</stats>\n" );
+
+ filesystem->Close( hFile );
+}
+
+#include "dod_basegrenade.h"
+
+//==========================================================
+// Called on physics entities that the player +uses ( if sv_turbophysics is on )
+// Here we want to exclude grenades
+//==========================================================
+bool CDODGameRules::CanEntityBeUsePushed( CBaseEntity *pEnt )
+{
+ CDODBaseGrenade *pGrenade = dynamic_cast<CDODBaseGrenade *>( pEnt );
+
+ if ( pGrenade )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Engine asks for the list of convars that should tag the server
+//-----------------------------------------------------------------------------
+void CDODGameRules::GetTaggedConVarList( KeyValues *pCvarTagList )
+{
+ BaseClass::GetTaggedConVarList( pCvarTagList );
+
+ KeyValues *pKV = new KeyValues( "tag" );
+ pKV->SetString( "convar", "mp_fadetoblack" );
+ pKV->SetString( "tag", "fadetoblack" );
+
+ pCvarTagList->AddSubKey( pKV );
+}
+
+#endif //indef CLIENT_DLL
+
+#ifdef CLIENT_DLL
+
+void CDODGameRules::SetRoundState( int iRoundState )
+{
+ m_iRoundState = iRoundState;
+
+ m_flLastRoundStateChangeTime = gpGlobals->curtime;
+}
+
+#endif // CLIENT_DLL
+
+bool CDODGameRules::IsBombingTeam( int team )
+{
+ if ( team == TEAM_ALLIES )
+ return m_bAlliesAreBombing;
+
+ if ( team == TEAM_AXIS )
+ return m_bAxisAreBombing;
+
+ return false;
+}
+
+bool CDODGameRules::IsConnectedUserInfoChangeAllowed( CBasePlayer *pPlayer )
+{
+#ifdef GAME_DLL
+ if( pPlayer )
+ {
+ int iPlayerTeam = pPlayer->GetTeamNumber();
+ if( ( iPlayerTeam == TEAM_ALLIES ) || ( iPlayerTeam == TEAM_AXIS ) )
+ return false;
+ }
+#else
+ int iLocalPlayerTeam = GetLocalPlayerTeam();
+ if( ( iLocalPlayerTeam == TEAM_ALLIES ) || ( iLocalPlayerTeam == TEAM_AXIS ) )
+ return false;
+#endif
+
+ return true;
+}
+
+
+#ifndef CLIENT_DLL
+
+ConVar dod_winter_never_drop_presents( "dod_winter_never_drop_presents", "0", FCVAR_CHEAT );
+ConVar dod_winter_always_drop_presents( "dod_winter_always_drop_presents", "0", FCVAR_CHEAT );
+ConVar dod_winter_present_drop_chance( "dod_winter_present_drop_chance", "0.2", FCVAR_CHEAT, "", true, 0.0, true, 1.0 );
+
+float CDODGameRules::GetPresentDropChance( void )
+{
+ if ( dod_winter_never_drop_presents.GetBool() )
+ {
+ return 0.0;
+ }
+
+ if ( dod_winter_always_drop_presents.GetBool() )
+ {
+ return 1.0;
+ }
+
+ if ( m_bWinterHolidayActive )
+ {
+ return dod_winter_present_drop_chance.GetFloat();
+ }
+
+ return 0.0;
+}
+
+#endif
+
+//=========================
+
+#ifndef CLIENT_DLL
+
+class CFuncTeamWall : public CBaseEntity
+{
+ DECLARE_DATADESC();
+ DECLARE_CLASS( CFuncTeamWall, CBaseEntity );
+
+public:
+ virtual void Spawn();
+ virtual bool KeyValue( const char *szKeyName, const char *szValue ) ;
+ virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const;
+
+ void WallTouch( CBaseEntity *pOther );
+
+ void DrawThink( void );
+
+private:
+ Vector m_vecMaxs;
+ Vector m_vecMins;
+
+ int m_iBlockTeam;
+
+ float m_flNextHintTime;
+
+ bool m_bShowWarning;
+};
+
+BEGIN_DATADESC( CFuncTeamWall )
+
+ DEFINE_KEYFIELD( m_iBlockTeam, FIELD_INTEGER, "blockteam" ),
+
+ DEFINE_KEYFIELD( m_vecMaxs, FIELD_VECTOR, "maxs" ),
+ DEFINE_KEYFIELD( m_vecMins, FIELD_VECTOR, "mins" ),
+
+ DEFINE_KEYFIELD( m_bShowWarning, FIELD_BOOLEAN, "warn" ),
+
+ DEFINE_THINKFUNC( DrawThink ),
+
+ DEFINE_FUNCTION( WallTouch ),
+
+END_DATADESC()
+
+LINK_ENTITY_TO_CLASS( func_team_wall, CFuncTeamWall );
+
+ConCommand cc_Load_Blocker_Walls( "load_enttext", Load_EntText, 0, FCVAR_CHEAT );
+
+ConVar showblockerwalls( "showblockerwalls", "0", FCVAR_CHEAT, "Set to 1 to visualize blocker walls" );
+
+void CFuncTeamWall::Spawn( void )
+{
+ SetMoveType( MOVETYPE_PUSH ); // so it doesn't get pushed by anything
+ SetModel( STRING( GetModelName() ) );
+ AddEffects( EF_NODRAW );
+ SetSolid( SOLID_BBOX );
+
+ // set our custom collision if we declared this ent through the .ent file
+ if ( m_vecMins != vec3_origin && m_vecMaxs != vec3_origin )
+ {
+ SetCollisionBounds( m_vecMins, m_vecMaxs );
+
+ // If we delcared an angle in the .ent file, make us OBB
+ if ( GetAbsAngles() != vec3_angle )
+ {
+ SetSolid( SOLID_OBB );
+ }
+ }
+
+ SetThink( &CFuncTeamWall::DrawThink );
+ SetNextThink( gpGlobals->curtime + 0.1 );
+
+ SetTouch( &CFuncTeamWall::WallTouch );
+ m_flNextHintTime = gpGlobals->curtime;
+}
+
+//-----------------------------------------------------------------------------
+// Parse data from a map file
+//-----------------------------------------------------------------------------
+bool CFuncTeamWall::KeyValue( const char *szKeyName, const char *szValue )
+{
+ if ( FStrEq( szKeyName, "mins" ))
+ {
+ UTIL_StringToVector( m_vecMins.Base(), szValue );
+ return true;
+ }
+
+ if ( FStrEq( szKeyName, "maxs" ))
+ {
+ UTIL_StringToVector( m_vecMaxs.Base(), szValue );
+ return true;
+ }
+
+ if ( FStrEq( szKeyName, "warn" ))
+ {
+ m_bShowWarning = atoi(szValue) > 0;
+ }
+
+ return BaseClass::KeyValue( szKeyName, szValue );
+}
+
+bool CFuncTeamWall::ShouldCollide( int collisionGroup, int contentsMask ) const
+{
+ bool bShouldCollide = false;
+
+ if ( collisionGroup == COLLISION_GROUP_PLAYER_MOVEMENT )
+ {
+ switch ( m_iBlockTeam )
+ {
+ case TEAM_UNASSIGNED:
+ bShouldCollide = ( contentsMask & ( CONTENTS_TEAM1 | CONTENTS_TEAM2 ) ) > 0;
+ break;
+
+ case TEAM_ALLIES:
+ bShouldCollide = ( contentsMask & CONTENTS_TEAM1 ) > 0;
+ break;
+
+ case TEAM_AXIS:
+ bShouldCollide = ( contentsMask & CONTENTS_TEAM2 ) > 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return bShouldCollide;
+}
+
+void CFuncTeamWall::WallTouch( CBaseEntity *pOther )
+{
+ if ( !m_bShowWarning )
+ return;
+
+ if ( pOther && pOther->IsPlayer() )
+ {
+ CDODPlayer *pPlayer = ToDODPlayer( pOther );
+
+ if ( pPlayer->GetTeamNumber() == m_iBlockTeam )
+ {
+ // show a "go away" icon
+ if ( m_flNextHintTime < gpGlobals->curtime )
+ {
+ pPlayer->HintMessage( "#dod_wrong_way" );
+
+ // global timer, but not critical to keep timer per player.
+ m_flNextHintTime = gpGlobals->curtime + 1.0;
+ }
+ }
+ }
+}
+
+void CFuncTeamWall::DrawThink( void )
+{
+ if ( showblockerwalls.GetBool() )
+ {
+ NDebugOverlay::EntityBounds( this, 255, 0, 0, 0, 0.2 );
+ }
+
+ SetNextThink( gpGlobals->curtime + 0.1 );
+}
+
+#endif
+
+
+#ifdef GAME_DLL
+
+ #include "modelentities.h"
+
+ #define SF_TEAM_WALL_NO_HINT (1<<1)
+
+ //-----------------------------------------------------------------------------
+ // Purpose: Visualizes a respawn room to the enemy team
+ //-----------------------------------------------------------------------------
+ class CFuncNewTeamWall : public CFuncBrush
+ {
+ DECLARE_CLASS( CFuncNewTeamWall, CFuncBrush );
+ public:
+ DECLARE_DATADESC();
+ DECLARE_SERVERCLASS();
+
+ virtual void Spawn( void );
+
+ virtual int UpdateTransmitState( void );
+ virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo );
+ virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const;
+
+ void WallTouch( CBaseEntity *pOther );
+
+ void SetActive( bool bActive );
+
+ private:
+ float m_flNextHintTime;
+ };
+
+ //===========================================================================================================
+
+ LINK_ENTITY_TO_CLASS( func_teamblocker, CFuncNewTeamWall );
+
+ BEGIN_DATADESC( CFuncNewTeamWall )
+ END_DATADESC()
+
+ IMPLEMENT_SERVERCLASS_ST( CFuncNewTeamWall, DT_FuncNewTeamWall )
+ END_SEND_TABLE()
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ void CFuncNewTeamWall::Spawn( void )
+ {
+ BaseClass::Spawn();
+
+ SetActive( true );
+
+ SetCollisionGroup( DOD_COLLISIONGROUP_BLOCKERWALL );
+
+ if ( FBitSet( m_spawnflags, SF_TEAM_WALL_NO_HINT ) == false )
+ {
+ SetTouch( &CFuncNewTeamWall::WallTouch );
+ m_flNextHintTime = gpGlobals->curtime;
+ }
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ int CFuncNewTeamWall::UpdateTransmitState()
+ {
+ return SetTransmitState( FL_EDICT_ALWAYS );
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose: Only transmit this entity to clients that aren't in our team
+ //-----------------------------------------------------------------------------
+ int CFuncNewTeamWall::ShouldTransmit( const CCheckTransmitInfo *pInfo )
+ {
+ return FL_EDICT_ALWAYS;
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ void CFuncNewTeamWall::SetActive( bool bActive )
+ {
+ if ( bActive )
+ {
+ // We're a trigger, but we want to be solid. Out ShouldCollide() will make
+ // us non-solid to members of the team that spawns here.
+ RemoveSolidFlags( FSOLID_TRIGGER );
+ RemoveSolidFlags( FSOLID_NOT_SOLID );
+ }
+ else
+ {
+ AddSolidFlags( FSOLID_NOT_SOLID );
+ AddSolidFlags( FSOLID_TRIGGER );
+ }
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ bool CFuncNewTeamWall::ShouldCollide( int collisionGroup, int contentsMask ) const
+ {
+ if ( GetTeamNumber() == TEAM_UNASSIGNED )
+ return false;
+
+ if ( collisionGroup == COLLISION_GROUP_PLAYER_MOVEMENT )
+ {
+ switch( GetTeamNumber() )
+ {
+ case TEAM_ALLIES:
+ if ( !(contentsMask & CONTENTS_TEAM1) )
+ return false;
+ break;
+
+ case TEAM_AXIS:
+ if ( !(contentsMask & CONTENTS_TEAM2) )
+ return false;
+ break;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ void CFuncNewTeamWall::WallTouch( CBaseEntity *pOther )
+ {
+ //if ( !m_bShowWarning )
+ // return;
+
+ if ( pOther && pOther->IsPlayer() )
+ {
+ CDODPlayer *pPlayer = ToDODPlayer( pOther );
+
+ if ( pPlayer->GetTeamNumber() == GetTeamNumber() )
+ {
+ // show a "go away" icon
+ if ( m_flNextHintTime < gpGlobals->curtime )
+ {
+ pPlayer->HintMessage( "#dod_wrong_way" );
+
+ // global timer, but not critical to keep timer per player.
+ m_flNextHintTime = gpGlobals->curtime + 1.0;
+ }
+ }
+ }
+ }
+
+#else
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ class C_FuncNewTeamWall : public C_BaseEntity
+ {
+ DECLARE_CLASS( C_FuncNewTeamWall, C_BaseEntity );
+ public:
+ DECLARE_CLIENTCLASS();
+
+ virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const;
+
+ virtual int DrawModel( int flags );
+ };
+
+ IMPLEMENT_CLIENTCLASS_DT( C_FuncNewTeamWall, DT_FuncNewTeamWall, CFuncNewTeamWall )
+ END_RECV_TABLE()
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ bool C_FuncNewTeamWall::ShouldCollide( int collisionGroup, int contentsMask ) const
+ {
+ if ( GetTeamNumber() == TEAM_UNASSIGNED )
+ return false;
+
+ if ( collisionGroup == COLLISION_GROUP_PLAYER_MOVEMENT )
+ {
+ switch( GetTeamNumber() )
+ {
+ case TEAM_ALLIES:
+ if ( !(contentsMask & CONTENTS_TEAM1) )
+ return false;
+ break;
+
+ case TEAM_AXIS:
+ if ( !(contentsMask & CONTENTS_TEAM2) )
+ return false;
+ break;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ int C_FuncNewTeamWall::DrawModel( int flags )
+ {
+ return 1;
+ }
+
+#endif
diff --git a/game/shared/dod/dod_gamerules.h b/game/shared/dod/dod_gamerules.h
new file mode 100644
index 0000000..2649fd8
--- /dev/null
+++ b/game/shared/dod/dod_gamerules.h
@@ -0,0 +1,526 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: The TF Game rules object
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef DOD_GAMERULES_H
+#define DOD_GAMERULES_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "teamplay_gamerules.h"
+#include "convar.h"
+#include "dod_shareddefs.h"
+#include "gamevars_shared.h"
+#include "weapon_dodbase.h"
+#include "dod_round_timer.h"
+
+#ifdef CLIENT_DLL
+ #include "c_baseplayer.h"
+#else
+ #include "player.h"
+ #include "dod_player.h"
+ #include "utlqueue.h"
+ #include "playerclass_info_parse.h"
+ #include "voice_gamemgr.h"
+ #include "dod_gamestats.h"
+#endif
+
+#ifdef CLIENT_DLL
+ #define CDODGameRules C_DODGameRules
+ #define CDODGameRulesProxy C_DODGameRulesProxy
+#else
+ extern IVoiceGameMgrHelper *g_pVoiceGameMgrHelper;
+ extern IUploadGameStats *gamestatsuploader;
+#endif
+
+#ifndef CLIENT_DLL
+
+ class CSpawnPoint : public CPointEntity
+ {
+ public:
+ bool IsDisabled() { return m_bDisabled; }
+ void InputEnable( inputdata_t &inputdata ) { m_bDisabled = false; }
+ void InputDisable( inputdata_t &inputdata ) { m_bDisabled = true; }
+
+ private:
+ bool m_bDisabled;
+ DECLARE_DATADESC();
+ };
+
+#endif
+
+class CDODGameRulesProxy : public CGameRulesProxy
+{
+public:
+ DECLARE_CLASS( CDODGameRulesProxy, CGameRulesProxy );
+ DECLARE_NETWORKCLASS();
+};
+
+class CDODGameRules;
+
+class CDODRoundStateInfo
+{
+public:
+ DODRoundState m_iRoundState;
+ const char *m_pStateName;
+
+ void (CDODGameRules::*pfnEnterState)(); // Init and deinit the state.
+ void (CDODGameRules::*pfnLeaveState)();
+ void (CDODGameRules::*pfnThink)(); // Do a PreThink() in this state.
+};
+
+typedef enum
+{
+ STARTROUND_ATTACK = 0,
+ STARTROUND_DEFEND,
+
+ STARTROUND_BEACH,
+
+ STARTROUND_ATTACK_TIMED,
+ STARTROUND_DEFEND_TIMED,
+
+ STARTROUND_FLAGS,
+} startround_voice_t;
+
+class CDODGamePlayRules
+{
+public:
+ DECLARE_CLASS_NOBASE( CDODGamePlayRules );
+ DECLARE_EMBEDDED_NETWORKVAR();
+
+ DECLARE_SIMPLE_DATADESC();
+
+ CDODGamePlayRules()
+ {
+ Reset();
+ }
+
+ // This virtual method is necessary to generate a vtable in all cases
+ // (DECLARE_PREDICTABLE will generate a vtable also)!
+ virtual ~CDODGamePlayRules() {}
+
+ void Reset( void )
+ {
+ //RespawnFactor
+ m_fAlliesRespawnFactor = 1.0f;
+ m_fAxisRespawnFactor = 1.0f;
+ }
+
+ //Respawn Factors
+ float m_fAlliesRespawnFactor; //How delayed are respawning players
+ float m_fAxisRespawnFactor; //1.0 is normal, 2.0 is twice as long
+
+ int m_iAlliesStartRoundVoice; // Which voice to play at round start
+ int m_iAxisStartRoundVoice;
+};
+
+
+//Mapper interface for gamerules
+class CDODDetect : public CBaseEntity
+{
+public:
+ DECLARE_CLASS( CDODDetect, CBaseEntity );
+
+ CDODDetect();
+ void Spawn( void );
+ virtual bool KeyValue( const char *szKeyName, const char *szValue );
+
+ bool IsMasteredOn( void );
+
+ inline CDODGamePlayRules *GetGamePlay() { return &m_GamePlayRules; }
+ CDODGamePlayRules m_GamePlayRules;
+
+private:
+// string_t m_sMaster;
+};
+
+class CDODViewVectors : public CViewVectors
+{
+public:
+ CDODViewVectors(
+ Vector vView,
+ Vector vHullMin,
+ Vector vHullMax,
+ Vector vDuckHullMin,
+ Vector vDuckHullMax,
+ Vector vDuckView,
+ Vector vObsHullMin,
+ Vector vObsHullMax,
+ Vector vDeadViewHeight,
+ Vector vProneHullMin,
+ Vector vProneHullMax ) :
+ CViewVectors(
+ vView,
+ vHullMin,
+ vHullMax,
+ vDuckHullMin,
+ vDuckHullMax,
+ vDuckView,
+ vObsHullMin,
+ vObsHullMax,
+ vDeadViewHeight )
+ {
+ m_vProneHullMin = vProneHullMin;
+ m_vProneHullMax = vProneHullMax;
+ }
+
+ Vector m_vProneHullMin;
+ Vector m_vProneHullMax;
+};
+
+//GAMERULES
+class CDODGameRules : public CTeamplayRules
+{
+public:
+ DECLARE_CLASS( CDODGameRules, CTeamplayRules );
+
+ virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 );
+
+ inline DODRoundState State_Get( void ) { return m_iRoundState; }
+
+ int GetSubTeam( int team );
+
+ bool IsGameUnderTimeLimit( void );
+ int GetTimeLeft( void );
+
+ int GetReinforcementTimerSeconds( int team, float flSpawnEligibleTime );
+
+ bool IsFriendlyFireOn( void );
+ bool IsInBonusRound( void );
+
+ // Get the view vectors for this mod.
+ virtual const CViewVectors* GetViewVectors() const;
+ virtual const CDODViewVectors *GetDODViewVectors() const;
+ virtual const unsigned char *GetEncryptionKey( void ) { return (unsigned char *)"Wl0u5B3F"; }
+
+ bool AwaitingReadyRestart( void ) { return m_bAwaitingReadyRestart; }
+ float GetRoundRestartTime( void ) { return m_flRestartRoundTime; }
+
+ bool IsInWarmup( void ) { return m_bInWarmup; }
+
+ bool IsBombingTeam( int team );
+
+ virtual bool IsConnectedUserInfoChangeAllowed( CBasePlayer *pPlayer );
+
+#ifndef CLIENT_DLL
+ float GetPresentDropChance( void ); // holiday 2011, presents instead of ammo boxes
+#endif
+
+#ifdef CLIENT_DLL
+
+ DECLARE_CLIENTCLASS_NOBASE(); // This makes datatables able to access our private vars.
+
+ void SetRoundState( int iRoundState );
+ float m_flLastRoundStateChangeTime;
+
+#else
+
+ DECLARE_SERVERCLASS_NOBASE(); // This makes datatables able to access our private vars.
+
+ CDODGameRules();
+ virtual ~CDODGameRules();
+
+ virtual void LevelShutdown( void );
+ void UploadLevelStats( void );
+
+ virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args );
+ virtual void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrc, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore );
+ virtual void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore, bool bIgnoreWorld = false );
+ void RadiusStun( const CTakeDamageInfo &info, const Vector &vecSrc, float flRadius );
+ virtual void Think();
+ virtual void PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info );
+ virtual void ClientDisconnected( edict_t *pClient );
+ virtual float FlPlayerFallDamage( CBasePlayer *pPlayer );
+
+ virtual const char *GetGameDescription( void )
+ {
+ return "Day of Defeat: Source";
+ }
+
+ void CreateStandardEntities( void );
+
+ virtual const char *GetChatPrefix( bool bTeamOnly, CBasePlayer *pPlayer );
+
+ CBaseEntity *GetPlayerSpawnSpot( CBasePlayer *pPlayer );
+ bool IsSpawnPointValid( CBaseEntity *pSpot, CBasePlayer *pPlayer );
+ virtual void PlayerSpawn( CBasePlayer *pPlayer );
+
+ int DODPointsForKill( CBasePlayer *pVictim, const CTakeDamageInfo &info );
+
+ //Round state machine
+ void State_Transition( DODRoundState newState );
+ void State_Enter( DODRoundState newState ); // Initialize the new state.
+ void State_Leave(); // Cleanup the previous state.
+ void State_Think(); // Update the current state.
+
+ CDODRoundStateInfo *m_pCurStateInfo; //Fn ptrs for the current state
+ float m_flStateTransitionTime; //Timer for round states
+
+ // Find the state info for the specified state.
+ static CDODRoundStateInfo* State_LookupInfo( DODRoundState state );
+
+ //State Functions
+ void State_Enter_INIT( void );
+ void State_Think_INIT( void );
+
+ void State_Enter_PREGAME( void );
+ void State_Think_PREGAME( void );
+
+ void State_Enter_STARTGAME( void );
+ void State_Think_STARTGAME( void );
+
+ void State_Enter_PREROUND( void );
+ void State_Think_PREROUND( void );
+
+ void State_Enter_RND_RUNNING( void );
+ void State_Think_RND_RUNNING( void );
+
+ void State_Enter_ALLIES_WIN( void );
+ void State_Think_ALLIES_WIN( void );
+
+ void State_Enter_AXIS_WIN( void );
+ void State_Think_AXIS_WIN( void );
+
+ void State_Enter_RESTART( void );
+ void State_Think_RESTART( void );
+
+ void SetInWarmup( bool bWarmup );
+ void CheckWarmup( void );
+ void CheckRestartRound( void );
+ void CheckRespawnWaves( void );
+
+ void InitTeams( void );
+
+ void RoundRespawn( void );
+ void CleanUpMap( void );
+ void ResetScores( void );
+
+ // Respawn everyone regardless of state - round reset
+ inline void RespawnAllPlayers( void ) { RespawnPlayers( true ); }
+
+ // Respawn only one team, players that are ready to spawn - wave reset
+ inline void RespawnTeam( int iTeam ) { RespawnPlayers( false, true, iTeam ); }
+
+ void RespawnPlayers( bool bForceRespawn, bool bTeam = false, int iTeam = TEAM_UNASSIGNED );
+
+ void FailSafeSpawnPlayersOnTeam( int iTeam );
+
+ bool IsPlayerClassOnTeam( int cls, int team );
+ bool CanPlayerJoinClass( CDODPlayer *pPlayer, int cls );
+ void ChooseRandomClass( CDODPlayer *pPlayer );
+ bool ReachedClassLimit( int team, int cls );
+ int CountPlayerClass( int team, int cls );
+ int GetClassLimit( int team, int cls );
+
+ int CountActivePlayers( void ); //How many players have chosen a team?
+
+ void SetWinningTeam( int team );
+ void PlayWinSong( int team );
+ void PlayStartRoundVoice( void );
+ void BroadcastSound( const char *sound );
+ void PlaySpawnSoundToTeam( const char *sound, int team );
+
+ int SelectDefaultTeam( void );
+
+ void CopyGamePlayLogic( const CDODGamePlayRules otherGamePlay );
+
+
+ void DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info );
+
+ virtual bool CanHavePlayerItem( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon );
+
+ bool TeamFull( int team_id );
+ bool TeamStacked( int iNewTeam, int iCurTeam );
+
+ const char *GetPlayerClassName( int cls, int team );
+
+ virtual void ClientSettingsChanged( CBasePlayer *pPlayer );
+
+ void CheckChatForReadySignal( CDODPlayer *pPlayer, const char *chatmsg );
+ bool AreAlliesReady( void ) { return m_bHeardAlliesReady; }
+ bool AreAxisReady( void ) { return m_bHeardAxisReady; }
+
+ void CreateOrJoinRespawnWave( CDODPlayer *pPlayer );
+
+ virtual bool InRoundRestart( void );
+
+ void SendTeamScoresEvent( void );
+
+ void WriteStatsFile( const char *pszLogName );
+
+ void AddTimerSeconds( int iSecondsToAdd );
+ int GetTimerSeconds( void );
+
+ void CapEvent( int event, int team );
+ int m_iLastAlliesCapEvent;
+ int m_iLastAxisCapEvent;
+
+ // Set the time at which the map was reset to 'now'
+ // and send an event with the time remaining until map change
+ void ResetMapTime( void );
+
+ virtual CBaseCombatWeapon *GetNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon );
+
+ virtual bool CanEntityBeUsePushed( CBaseEntity *pEnt );
+
+ virtual void CalcDominationAndRevenge( CDODPlayer *pAttacker, CDODPlayer *pVictim, int *piDeathFlags );
+
+ float m_flNextFailSafeWaveCheckTime;
+
+ CUtlVector<EHANDLE> *GetSpawnPointListForTeam( int iTeam );
+
+ virtual void GetTaggedConVarList( KeyValues *pCvarTagList );
+
+protected:
+ virtual void GoToIntermission( void );
+ virtual bool UseSuicidePenalty() { return false; }
+
+ void CheckPlayerPositions( void );
+
+private:
+ bool CheckTimeLimit( void );
+ bool CheckWinLimit( void );
+
+ void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, bool bIgnoreWorld );
+ float GetExplosionDamageAdjustment(Vector & vecSrc, Vector & vecEnd, CBaseEntity *pTarget, CBaseEntity *pEntityToIgnore); // returns multiplier between 0.0 and 1.0 that is the percentage of any damage done from vecSrc to vecEnd that actually makes it.
+ float GetAmountOfEntityVisible(Vector & src, CBaseEntity *pTarget, CBaseEntity *pEntityToIgnore); // returns a value from 0 to 1 that is the percentage of player visible from src.
+
+ void CheckLevelInitialized( void );
+ bool m_bLevelInitialized;
+
+ int m_iSpawnPointCount_Allies; //number of allies spawns on the map
+ int m_iSpawnPointCount_Axis; //number of axis spawns on the map
+
+ #define MAX_PLAYERCLASSES_PER_TEAM 16
+
+ PLAYERCLASS_FILE_INFO_HANDLE m_hPlayerClassInfoHandles[2][MAX_PLAYERCLASSES_PER_TEAM];
+
+ // restart and warmup variables
+ float m_flWarmupTimeEnds;
+ float m_flNextPeriodicThink;
+
+ Vector2D m_vecPlayerPositions[MAX_PLAYERS];
+
+
+ //BELOW HERE NEED TO BE HOOKED UP
+
+
+ int m_iNumAlliesAlive; //the number of players alive on each team
+ int m_iNumAxisAlive;
+ int m_iNumAlliesOnTeam; //the number of players on each team
+ int m_iNumAxisOnTeam;
+
+ bool m_bClanMatch;
+ bool m_bClanMatchActive;
+
+ float GetMaxWaveTime( int iTeam );
+ float GetWaveTime( int iTeam );
+ void AddWaveTime( int team, float flTime );
+ void PopWaveTime( int team );
+
+ void DetectGameRules( void );
+
+ bool m_bHeardAlliesReady;
+ bool m_bHeardAxisReady;
+
+ bool m_bUsingTimer;
+ int m_iTimerWinTeam;
+ CHandle< CDODRoundTimer > m_pRoundTimer;
+
+ bool m_bPlayTimerWarning_1Minute;
+ bool m_bPlayTimerWarning_2Minute;
+
+ bool m_bInitialSpawn; // first time activating? longer wait time for people to join
+
+ bool m_bChangeLevelOnRoundEnd;
+
+#endif //CLIENT_DLL
+
+ CNetworkVarEmbedded( CDODGamePlayRules, m_GamePlayRules );
+
+ CNetworkVar( DODRoundState, m_iRoundState );
+
+ #define DOD_RESPAWN_QUEUE_SIZE 10
+
+ CNetworkArray( float, m_AlliesRespawnQueue, DOD_RESPAWN_QUEUE_SIZE );
+ CNetworkArray( float, m_AxisRespawnQueue, DOD_RESPAWN_QUEUE_SIZE );
+
+ CNetworkVar( int, m_iAlliesRespawnHead );
+ CNetworkVar( int, m_iAlliesRespawnTail );
+
+ CNetworkVar( int, m_iAxisRespawnHead );
+ CNetworkVar( int, m_iAxisRespawnTail );
+
+ int m_iNumAlliesRespawnWaves;
+ int m_iNumAxisRespawnWaves;
+
+ CNetworkVar( bool, m_bInWarmup );
+ CNetworkVar( bool, m_bAwaitingReadyRestart );
+ CNetworkVar( float, m_flRestartRoundTime );
+ CNetworkVar( float, m_flMapResetTime ); // time that the map was reset
+
+ CNetworkVar( bool, m_bAlliesAreBombing );
+ CNetworkVar( bool, m_bAxisAreBombing );
+
+#ifndef CLIENT_DLL
+public:
+ // Stats
+ void Stats_PlayerKill( int team, int cls );
+ void Stats_PlayerCap( int team, int cls );
+ void Stats_PlayerDefended( int team, int cls );
+ void Stats_WeaponFired( int weaponID );
+ void Stats_WeaponHit( int weaponID, float flDist );
+ int Stats_WeaponDistanceToBucket( int weaponID, float flDist );
+
+ float m_flSecondsPlayedPerClass_Allies[7];
+ float m_flSecondsPlayedPerClass_Axis[7];
+
+ int m_iStatsKillsPerClass_Allies[6];
+ int m_iStatsKillsPerClass_Axis[6];
+
+ int m_iStatsSpawnsPerClass_Allies[6];
+ int m_iStatsSpawnsPerClass_Axis[6];
+
+ int m_iStatsCapsPerClass_Allies[6];
+ int m_iStatsCapsPerClass_Axis[6];
+
+ int m_iStatsDefensesPerClass_Allies[6];
+ int m_iStatsDefensesPerClass_Axis[6];
+
+ int m_iWeaponShotsFired[WEAPON_MAX];
+ int m_iWeaponShotsHit[WEAPON_MAX];
+ int m_iWeaponDistanceBuckets[WEAPON_MAX][DOD_NUM_WEAPON_DISTANCE_BUCKETS]; // distances of buckets are defined per-weapon
+
+ // List of spawn points
+ CUtlVector<EHANDLE> m_AlliesSpawnPoints;
+ CUtlVector<EHANDLE> m_AxisSpawnPoints;
+
+ bool m_bWinterHolidayActive;
+
+#endif // ndef CLIENTDLL
+};
+
+//-----------------------------------------------------------------------------
+// Gets us at the team fortress game rules
+//-----------------------------------------------------------------------------
+
+inline CDODGameRules* DODGameRules()
+{
+ return static_cast<CDODGameRules*>(g_pGameRules);
+}
+
+#ifdef CLIENT_DLL
+
+#else
+ bool EntityPlacementTest( CBaseEntity *pMainEnt, const Vector &vOrigin, Vector &outPos, bool bDropToGround );
+#endif //CLIENT_DLL
+
+
+#endif // DOD_GAMERULES_H
diff --git a/game/shared/dod/dod_player_shared.cpp b/game/shared/dod/dod_player_shared.cpp
new file mode 100644
index 0000000..ec35acf
--- /dev/null
+++ b/game/shared/dod/dod_player_shared.cpp
@@ -0,0 +1,1396 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "dod_gamerules.h"
+#include "takedamageinfo.h"
+#include "dod_shareddefs.h"
+#include "effect_dispatch_data.h"
+
+#include "weapon_dodbase.h"
+#include "weapon_dodbipodgun.h"
+#include "weapon_dodbaserpg.h"
+#include "weapon_dodsniper.h"
+
+#include "movevars_shared.h"
+#include "engine/IEngineSound.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "engine/ivdebugoverlay.h"
+#include "obstacle_pushaway.h"
+#include "props_shared.h"
+
+#include "decals.h"
+#include "util_shared.h"
+
+#ifdef CLIENT_DLL
+
+ #include "c_dod_player.h"
+ #include "prediction.h"
+ #include "clientmode_dod.h"
+ #include "vgui_controls/AnimationController.h"
+
+ #define CRecipientFilter C_RecipientFilter
+
+#else
+
+ #include "dod_player.h"
+
+#endif
+
+ConVar dod_bonusround( "dod_bonusround", "1", FCVAR_REPLICATED, "If true, the winners of the round can attack in the intermission." );
+ConVar sv_showimpacts("sv_showimpacts", "0", FCVAR_REPLICATED | FCVAR_CHEAT, "Shows client (red) and server (blue) bullet impact point" );
+
+void DispatchEffect( const char *pName, const CEffectData &data );
+
+bool CDODPlayer::CanMove( void ) const
+{
+ bool bValidMoveState = (State_Get() == STATE_ACTIVE || State_Get() == STATE_OBSERVER_MODE);
+
+ if ( !bValidMoveState )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// BUG! This is not called on the client at respawn, only first spawn!
+void CDODPlayer::SharedSpawn()
+{
+ BaseClass::SharedSpawn();
+
+ // Reset the animation state or we will animate to standing
+ // when we spawn
+
+ m_Shared.SetJumping( false );
+
+ m_flMinNextStepSoundTime = gpGlobals->curtime;
+
+ m_bPlayingProneMoveSound = false;
+}
+
+float GetDensityFromMaterial( surfacedata_t *pSurfaceData )
+{
+ float flMaterialMod = 1.0f;
+
+ Assert( pSurfaceData );
+
+ // material mod is how many points of damage it costs to go through
+ // 1 unit of the material
+
+ switch( pSurfaceData->game.material )
+ {
+ //super soft
+// case CHAR_TEX_LEAVES:
+// flMaterialMod = 1.2f;
+// break;
+
+ case CHAR_TEX_FLESH:
+ flMaterialMod = 1.35f;
+ break;
+
+ //soft
+// case CHAR_TEX_STUCCO:
+// case CHAR_TEX_SNOW:
+ case CHAR_TEX_GLASS:
+ case CHAR_TEX_WOOD:
+ case CHAR_TEX_TILE:
+ flMaterialMod = 1.8f;
+ break;
+
+ //hard
+// case CHAR_TEX_SKY:
+// case CHAR_TEX_ROCK:
+// case CHAR_TEX_SAND:
+ case CHAR_TEX_CONCRETE:
+ case CHAR_TEX_DIRT: // "sand"
+ flMaterialMod = 6.6f;
+ break;
+
+ //really hard
+// case CHAR_TEX_HEAVYMETAL:
+ case CHAR_TEX_GRATE:
+ case CHAR_TEX_METAL:
+ flMaterialMod = 13.5f;
+ break;
+
+ case 'X': // invisible collision material
+ flMaterialMod = 0.1f;
+ break;
+
+ //medium
+// case CHAR_TEX_BRICK:
+// case CHAR_TEX_GRAVEL:
+// case CHAR_TEX_GRASS:
+ default:
+
+#ifndef CLIENT_DLL
+ AssertMsg( 0, UTIL_VarArgs( "Material has unknown materialmod - '%c' \n", pSurfaceData->game.material ) );
+#endif
+
+ flMaterialMod = 5.0f;
+ break;
+ }
+
+ Assert( flMaterialMod > 0 );
+
+ return flMaterialMod;
+}
+
+static bool TraceToExit( const Vector &start,
+ const Vector &dir,
+ Vector &end,
+ const float flStepSize,
+ const float flMaxDistance )
+{
+ float flDistance = 0;
+ Vector last = start;
+
+ while ( flDistance < flMaxDistance )
+ {
+ flDistance += flStepSize;
+
+ // no point in tracing past the max distance.
+ // if this check fails, we save ourselves a traceline later
+ if ( flDistance > flMaxDistance )
+ {
+ flDistance = flMaxDistance;
+ }
+
+ end = start + flDistance * dir;
+
+ // point contents fails to return proper contents inside a func_detail brush, eg the dod_flash
+ // stairs
+
+ //int contents = UTIL_PointContents( end );
+
+ trace_t tr;
+ UTIL_TraceLine( end, end, MASK_SOLID | CONTENTS_HITBOX, NULL, &tr );
+
+ //if ( (UTIL_PointContents ( end ) & MASK_SOLID) == 0 )
+
+ if ( !tr.startsolid )
+ {
+ // found first free point
+ return true;
+ }
+ }
+
+ return false;
+}
+
+#include "ammodef.h"
+
+#define NEW_HITBOX_GROUP_CODE 1
+#undef ARM_PENETRATION
+
+#ifndef CLIENT_DLL
+#include "ndebugoverlay.h"
+#endif
+void CDODPlayer::FireBullets( const FireBulletsInfo_t &info )
+{
+ trace_t tr;
+ trace_t reverseTr; //Used to find exit points
+ static int iMaxPenetrations = 6;
+ int iPenetrations = 0;
+ float flDamage = info.m_flDamage; //Remaining damage in the bullet
+ Vector vecSrc = info.m_vecSrc;
+ Vector vecEnd = vecSrc + info.m_vecDirShooting * info.m_flDistance;
+
+ static int iTraceMask = ( ( MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_HITBOX | CONTENTS_PRONE_HELPER ) & ~CONTENTS_GRATE );
+
+ CBaseEntity *pLastHitEntity = this; // start with us so we don't trace ourselves
+
+ int iDamageType = GetAmmoDef()->DamageType( info.m_iAmmoType );
+ int iCollisionGroup = COLLISION_GROUP_NONE;
+
+#ifdef GAME_DLL
+ int iNumHeadshots = 0;
+#endif
+
+ while ( flDamage > 0 && iPenetrations < iMaxPenetrations )
+ {
+ //DevMsg( 2, "penetration: %d, starting dmg: %.1f\n", iPenetrations, flDamage );
+
+ CBaseEntity *pPreviousHit = pLastHitEntity;
+
+ // skip the shooter always
+ CTraceFilterSkipTwoEntities ignoreShooterAndPrevious( this, pPreviousHit, iCollisionGroup );
+ UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &ignoreShooterAndPrevious, &tr );
+
+ const float rayExtension = 40.0f;
+ UTIL_ClipTraceToPlayers( vecSrc, vecEnd + info.m_vecDirShooting * rayExtension, iTraceMask, &ignoreShooterAndPrevious, &tr );
+
+ if ( tr.fraction == 1.0f )
+ break; // we didn't hit anything, stop tracing shoot
+
+ // New hitbox code that uses hitbox groups instead of trying to trace
+ // through the player
+ if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() )
+ {
+ switch( tr.hitgroup )
+ {
+#ifdef GAME_DLL
+ case HITGROUP_HEAD:
+ {
+ if ( tr.m_pEnt->GetTeamNumber() != GetTeamNumber() )
+ {
+ iNumHeadshots++;
+ }
+ }
+ break;
+#endif
+
+ case HITGROUP_LEFTARM:
+ case HITGROUP_RIGHTARM:
+ {
+ //DevMsg( 2, "Hit arms, tracing against alt hitboxes.. \n" );
+
+ CDODPlayer *pPlayer = ToDODPlayer( tr.m_pEnt );
+
+ // set hitbox set to "dod_no_arms"
+ pPlayer->SetHitboxSet( 1 );
+
+ trace_t newTr;
+
+ // re-fire the trace
+ UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &ignoreShooterAndPrevious, &newTr );
+
+ // if we hit the same player in the chest
+ if ( tr.m_pEnt == newTr.m_pEnt )
+ {
+ //DevMsg( 2, ".. and we hit the chest.\n" );
+
+ Assert( tr.hitgroup != newTr.hitgroup ); // If we hit this, hitbox sets are broken
+
+ // use that damage instead
+ tr = newTr;
+ }
+
+ // set hitboxes back to "dod"
+ pPlayer->SetHitboxSet( 0 );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ pLastHitEntity = tr.m_pEnt;
+
+ if ( sv_showimpacts.GetBool() )
+ {
+#ifdef CLIENT_DLL
+ // draw red client impact markers
+ debugoverlay->AddBoxOverlay( tr.endpos, Vector(-1,-1,-1), Vector(1,1,1), QAngle(0,0,0), 255, 0, 0, 127, 4 );
+
+ if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() )
+ {
+ C_BasePlayer *player = ToBasePlayer( tr.m_pEnt );
+ player->DrawClientHitboxes( 4, true );
+ }
+#else
+ // draw blue server impact markers
+ NDebugOverlay::Box( tr.endpos, Vector(-1,-1,-1), Vector(1,1,1), 0,0,255,127, 4 );
+
+ if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() )
+ {
+ CBasePlayer *player = ToBasePlayer( tr.m_pEnt );
+ player->DrawServerHitboxes( 4, true );
+ }
+#endif
+ }
+
+#ifdef CLIENT_DLL
+ // See if the bullet ended up underwater + started out of the water
+ if ( enginetrace->GetPointContents( tr.endpos ) & (CONTENTS_WATER|CONTENTS_SLIME) )
+ {
+ trace_t waterTrace;
+ UTIL_TraceLine( vecSrc, tr.endpos, (MASK_SHOT|CONTENTS_WATER|CONTENTS_SLIME), this, iCollisionGroup, &waterTrace );
+
+ if( waterTrace.allsolid != 1 )
+ {
+ CEffectData data;
+ data.m_vOrigin = waterTrace.endpos;
+ data.m_vNormal = waterTrace.plane.normal;
+ data.m_flScale = random->RandomFloat( 8, 12 );
+
+ if ( waterTrace.contents & CONTENTS_SLIME )
+ {
+ data.m_fFlags |= FX_WATER_IN_SLIME;
+ }
+
+ DispatchEffect( "gunshotsplash", data );
+ }
+ }
+ else
+ {
+ //Do Regular hit effects
+
+ // Don't decal nodraw surfaces
+ if ( !( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) )
+ {
+ CBaseEntity *pEntity = tr.m_pEnt;
+ if ( !( !friendlyfire.GetBool() && pEntity && pEntity->GetTeamNumber() == GetTeamNumber() ) )
+ {
+ UTIL_ImpactTrace( &tr, iDamageType );
+ }
+ }
+ }
+#endif
+
+ // Get surface where the bullet entered ( if it had different surfaces on enter and exit )
+ surfacedata_t *pSurfaceData = physprops->GetSurfaceData( tr.surface.surfaceProps );
+ Assert( pSurfaceData );
+
+ float flMaterialMod = GetDensityFromMaterial(pSurfaceData);
+
+ if ( iDamageType & DMG_MACHINEGUN )
+ {
+ flMaterialMod *= 0.65;
+ }
+
+ // try to penetrate object
+ Vector penetrationEnd;
+ float flMaxDistance = flDamage / flMaterialMod;
+
+#ifndef CLIENT_DLL
+ ClearMultiDamage();
+
+ float flActualDamage = flDamage;
+
+ CTakeDamageInfo dmgInfo( info.m_pAttacker, info.m_pAttacker, flActualDamage, iDamageType );
+ CalculateBulletDamageForce( &dmgInfo, info.m_iAmmoType, info.m_vecDirShooting, tr.endpos );
+ tr.m_pEnt->DispatchTraceAttack( dmgInfo, info.m_vecDirShooting, &tr );
+
+ DevMsg( 2, "Giving damage ( %.1f ) to entity of type %s\n", flActualDamage, tr.m_pEnt->GetClassname() );
+
+ TraceAttackToTriggers( dmgInfo, tr.startpos, tr.endpos, info.m_vecDirShooting );
+#endif
+
+ int stepsize = 16;
+
+ // displacement always stops the bullet
+ if ( tr.IsDispSurface() )
+ {
+ DevMsg( 2, "bullet was stopped by displacement\n" );
+ ApplyMultiDamage();
+ break;
+ }
+
+ // trace through the solid to find the exit point and how much material we went through
+ if ( !TraceToExit( tr.endpos, info.m_vecDirShooting, penetrationEnd, stepsize, flMaxDistance ) )
+ {
+ DevMsg( 2, "bullet was stopped\n" );
+ ApplyMultiDamage();
+ break;
+ }
+
+ // find exact penetration exit
+ CTraceFilterSimple ignoreShooter( this, iCollisionGroup );
+ UTIL_TraceLine( penetrationEnd, tr.endpos, iTraceMask, &ignoreShooter, &reverseTr );
+
+ // Now we can apply the damage, after we have traced the entity
+ // so it doesn't break or die before we have a change to test against it
+#ifndef CLIENT_DLL
+ ApplyMultiDamage();
+#endif
+
+ // Continue looking for the exit point
+ if( reverseTr.m_pEnt != tr.m_pEnt && reverseTr.m_pEnt != NULL )
+ {
+ // something was blocking, trace again
+ CTraceFilterSkipTwoEntities ignoreShooterAndBlocker( this, reverseTr.m_pEnt, iCollisionGroup );
+ UTIL_TraceLine( penetrationEnd, tr.endpos, iTraceMask, &ignoreShooterAndBlocker, &reverseTr );
+ }
+
+ if ( sv_showimpacts.GetBool() )
+ {
+ debugoverlay->AddLineOverlay( penetrationEnd, reverseTr.endpos, 255, 0, 0, true, 3.0 );
+ }
+
+ // penetration was successful
+
+#ifdef CLIENT_DLL
+ // bullet did penetrate object, exit Decal
+ if ( !( reverseTr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) )
+ {
+ CBaseEntity *pEntity = reverseTr.m_pEnt;
+ if ( !( !friendlyfire.GetBool() && pEntity && pEntity->GetTeamNumber() == GetTeamNumber() ) )
+ {
+ UTIL_ImpactTrace( &reverseTr, iDamageType );
+ }
+ }
+#endif
+
+ //setup new start end parameters for successive trace
+
+ // New start point is our last exit point
+ vecSrc = reverseTr.endpos + /* 1.0 * */ info.m_vecDirShooting;
+
+ // Reduce bullet damage by material and distanced travelled through that material
+ // if it is < 0 we won't go through the loop again
+ float flTraceDistance = VectorLength( reverseTr.endpos - tr.endpos );
+
+ flDamage -= flMaterialMod * flTraceDistance;
+
+ if( flDamage > 0 )
+ {
+ DevMsg( 2, "Completed penetration, new damage is %.1f\n", flDamage );
+ }
+ else
+ {
+ DevMsg( 2, "bullet was stopped\n" );
+ }
+
+ iPenetrations++;
+ }
+
+#ifdef GAME_DLL
+ HandleHeadshotAchievement( iNumHeadshots );
+#endif
+}
+
+void CDODPlayer::SetSprinting( bool bIsSprinting )
+{
+ m_Shared.SetSprinting( bIsSprinting );
+}
+
+bool CDODPlayer::IsSprinting( void )
+{
+ float flVelSqr = GetAbsVelocity().LengthSqr();
+
+ return m_Shared.m_bIsSprinting && ( flVelSqr > 0.5f );
+}
+
+bool CDODPlayer::CanAttack( void )
+{
+ if ( IsSprinting() )
+ return false;
+
+ if ( GetMoveType() == MOVETYPE_LADDER )
+ return false;
+
+ if ( m_Shared.IsJumping() )
+ return false;
+
+ if ( m_Shared.IsDefusing() )
+ return false;
+
+ // cannot attack while prone moving. except if you have a bazooka
+ if ( m_Shared.IsProne() && GetAbsVelocity().LengthSqr() > 1 )
+ {
+ return false;
+ }
+
+ if( m_Shared.IsGoingProne() || m_Shared.IsGettingUpFromProne() )
+ {
+ return false;
+ }
+
+ CDODGameRules *rules = DODGameRules();
+
+ Assert( rules );
+
+ DODRoundState state = rules->State_Get();
+
+ if ( dod_bonusround.GetBool() )
+ {
+ if ( GetTeamNumber() == TEAM_ALLIES )
+ {
+ return ( state == STATE_RND_RUNNING || state == STATE_ALLIES_WIN );
+ }
+ else
+ {
+ return ( state == STATE_RND_RUNNING || state == STATE_AXIS_WIN );
+ }
+ }
+ else
+ return ( state == STATE_RND_RUNNING );
+}
+
+
+void CDODPlayer::SetAnimation( PLAYER_ANIM playerAnim )
+{
+ // In DoD, its CPlayerAnimState object manages ALL the animation state.
+ return;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input :
+// Output : const Vector
+//-----------------------------------------------------------------------------
+const Vector CDODPlayer::GetPlayerMins( void ) const
+{
+ if ( IsObserver() )
+ {
+ return VEC_OBS_HULL_MIN;
+ }
+ else
+ {
+ if ( GetFlags() & FL_DUCKING )
+ {
+ return VEC_DUCK_HULL_MIN;
+ }
+ else if ( m_Shared.IsProne() )
+ {
+ return VEC_PRONE_HULL_MIN;
+ }
+ else
+ {
+ return VEC_HULL_MIN;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input :
+// Output : const Vector
+//-----------------------------------------------------------------------------
+const Vector CDODPlayer::GetPlayerMaxs( void ) const
+{
+ if ( IsObserver() )
+ {
+ return VEC_OBS_HULL_MAX_SCALED( this );
+ }
+ else
+ {
+ if ( GetFlags() & FL_DUCKING )
+ {
+ return VEC_DUCK_HULL_MAX_SCALED( this );
+ }
+ else if ( m_Shared.IsProne() )
+ {
+ return VEC_PRONE_HULL_MAX_SCALED( this );
+ }
+ else
+ {
+ return VEC_HULL_MAX_SCALED( this );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : collisionGroup -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CDODPlayer::ShouldCollide( int collisionGroup, int contentsMask ) const
+{
+ if ( collisionGroup == COLLISION_GROUP_PLAYER_MOVEMENT || collisionGroup == COLLISION_GROUP_PROJECTILE )
+ {
+ switch( GetTeamNumber() )
+ {
+ case TEAM_ALLIES:
+ if ( !( contentsMask & CONTENTS_TEAM2 ) )
+ return false;
+ break;
+
+ case TEAM_AXIS:
+ if ( !( contentsMask & CONTENTS_TEAM1 ) )
+ return false;
+ break;
+ }
+ }
+
+ return BaseClass::ShouldCollide( collisionGroup, contentsMask );
+}
+
+// --------------------------------------------------------------------------------------------------- //
+// CDODPlayerShared implementation.
+// --------------------------------------------------------------------------------------------------- //
+
+CDODPlayerShared::CDODPlayerShared()
+{
+ m_bProne = false;
+ m_bForceProneChange = false;
+ m_flNextProneCheck = 0;
+
+ m_flSlowedUntilTime = 0;
+
+ m_flUnProneTime = 0;
+ m_flGoProneTime = 0;
+
+ m_flDeployedHeight = STANDING_DEPLOY_HEIGHT;
+ m_flDeployChangeTime = gpGlobals->curtime;
+
+ SetDesiredPlayerClass( PLAYERCLASS_UNDEFINED );
+
+ m_flLastViewAnimationTime = gpGlobals->curtime;
+
+ m_pViewOffsetAnim = NULL;
+}
+
+CDODPlayerShared::~CDODPlayerShared()
+{
+ if ( m_pViewOffsetAnim )
+ {
+ delete m_pViewOffsetAnim;
+ m_pViewOffsetAnim = NULL;
+ }
+}
+
+void CDODPlayerShared::Init( CDODPlayer *pPlayer )
+{
+ m_pOuter = pPlayer;
+}
+
+bool CDODPlayerShared::IsDucking( void ) const
+{
+ return !!( m_pOuter->GetFlags() & FL_DUCKING );
+}
+
+bool CDODPlayerShared::IsProne() const
+{
+ return m_bProne;
+}
+
+bool CDODPlayerShared::IsGettingUpFromProne() const
+{
+ return ( m_flUnProneTime > 0 );
+}
+
+bool CDODPlayerShared::IsGoingProne() const
+{
+ return ( m_flGoProneTime > 0 );
+}
+
+void CDODPlayerShared::SetSprinting( bool bSprinting )
+{
+ if ( bSprinting && !m_bIsSprinting )
+ {
+ StartSprinting();
+
+ // only one penalty per key press
+ if ( m_bGaveSprintPenalty == false )
+ {
+ m_flStamina -= INITIAL_SPRINT_STAMINA_PENALTY;
+ m_bGaveSprintPenalty = true;
+ }
+ }
+ else if ( !bSprinting && m_bIsSprinting )
+ {
+ StopSprinting();
+ }
+}
+
+// this is reset when we let go of the sprint key
+void CDODPlayerShared::ResetSprintPenalty( void )
+{
+ m_bGaveSprintPenalty = false;
+}
+
+void CDODPlayerShared::StartSprinting( void )
+{
+ m_bIsSprinting = true;
+
+#ifndef CLIENT_DLL
+ m_pOuter->RemoveHintTimer( HINT_USE_SPRINT );
+#endif
+}
+
+void CDODPlayerShared::StopSprinting( void )
+{
+ m_bIsSprinting = false;
+}
+
+void CDODPlayerShared::SetProne( bool bProne, bool bNoAnimation /* = false */ )
+{
+ m_bProne = bProne;
+
+ if ( bNoAnimation )
+ {
+ m_flGoProneTime = 0;
+ m_flUnProneTime = 0;
+
+ // cancel the view animation!
+ m_bForceProneChange = true;
+ }
+
+ if ( !bProne /*&& IsSniperZoomed()*/ ) // forceunzoom for going prone is in StartGoingProne
+ {
+ ForceUnzoom();
+ }
+}
+
+void CDODPlayerShared::SetJumping( bool bJumping )
+{
+ m_bJumping = bJumping;
+
+ if ( IsSniperZoomed() )
+ {
+ ForceUnzoom();
+ }
+}
+
+void CDODPlayerShared::ForceUnzoom( void )
+{
+ CWeaponDODBase *pWeapon = GetActiveDODWeapon();
+ if( pWeapon && ( pWeapon->GetDODWpnData().m_WeaponType & WPN_MASK_GUN ) )
+ {
+ CDODSniperWeapon *pSniper = dynamic_cast<CDODSniperWeapon *>(pWeapon);
+
+ if ( pSniper )
+ {
+ pSniper->ZoomOut();
+ }
+ }
+}
+
+bool CDODPlayerShared::IsBazookaDeployed( void ) const
+{
+ CWeaponDODBase *pWeapon = GetActiveDODWeapon();
+ if( pWeapon && pWeapon->GetDODWpnData().m_WeaponType == WPN_TYPE_BAZOOKA )
+ {
+ CDODBaseRocketWeapon *pBazooka = (CDODBaseRocketWeapon *)pWeapon;
+ return pBazooka->IsDeployed() && !pBazooka->m_bInReload;
+ }
+
+ return false;
+}
+
+bool CDODPlayerShared::IsBazookaOnlyDeployed( void ) const
+{
+ CWeaponDODBase *pWeapon = GetActiveDODWeapon();
+ if( pWeapon && pWeapon->GetDODWpnData().m_WeaponType == WPN_TYPE_BAZOOKA )
+ {
+ CDODBaseRocketWeapon *pBazooka = (CDODBaseRocketWeapon *)pWeapon;
+ return pBazooka->IsDeployed();
+ }
+
+ return false;
+}
+
+bool CDODPlayerShared::IsSniperZoomed( void ) const
+{
+ CWeaponDODBase *pWeapon = GetActiveDODWeapon();
+ if( pWeapon && ( pWeapon->GetDODWpnData().m_WeaponType & WPN_MASK_GUN ) )
+ {
+ CWeaponDODBaseGun *pGun = (CWeaponDODBaseGun *)pWeapon;
+ Assert( pGun );
+ return pGun->IsSniperZoomed();
+ }
+
+ return false;
+}
+
+bool CDODPlayerShared::IsInMGDeploy( void ) const
+{
+ CWeaponDODBase *pWeapon = GetActiveDODWeapon();
+ if( pWeapon && pWeapon->GetDODWpnData().m_WeaponType == WPN_TYPE_MG )
+ {
+ CDODBipodWeapon *pMG = dynamic_cast<CDODBipodWeapon *>( pWeapon );
+ Assert( pMG );
+ return pMG->IsDeployed();
+ }
+
+ return false;
+}
+
+bool CDODPlayerShared::IsProneDeployed( void ) const
+{
+ return ( IsProne() && IsInMGDeploy() );
+}
+
+bool CDODPlayerShared::IsSandbagDeployed( void ) const
+{
+ return ( !IsProne() && IsInMGDeploy() );
+}
+
+void CDODPlayerShared::SetDesiredPlayerClass( int playerclass )
+{
+ m_iDesiredPlayerClass = playerclass;
+}
+
+int CDODPlayerShared::DesiredPlayerClass( void )
+{
+ return m_iDesiredPlayerClass;
+}
+
+void CDODPlayerShared::SetPlayerClass( int playerclass )
+{
+ m_iPlayerClass = playerclass;
+}
+
+int CDODPlayerShared::PlayerClass( void )
+{
+ return m_iPlayerClass;
+}
+
+void CDODPlayerShared::SetStamina( float flStamina )
+{
+ m_flStamina = clamp( flStamina, 0, 100 );
+}
+
+CWeaponDODBase* CDODPlayerShared::GetActiveDODWeapon() const
+{
+ CBaseCombatWeapon *pWeapon = m_pOuter->GetActiveWeapon();
+ if ( pWeapon )
+ {
+ Assert( dynamic_cast< CWeaponDODBase* >( pWeapon ) == static_cast< CWeaponDODBase* >( pWeapon ) );
+ return static_cast< CWeaponDODBase* >( pWeapon );
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+void CDODPlayerShared::SetDeployed( bool bDeployed, float flHeight /* = -1 */ )
+{
+ if( gpGlobals->curtime - m_flDeployChangeTime < 0.2 )
+ {
+ Assert(0);
+ }
+
+ m_flDeployChangeTime = gpGlobals->curtime;
+ m_vecDeployedAngles = m_pOuter->EyeAngles();
+
+ if( flHeight > 0 )
+ {
+ m_flDeployedHeight = flHeight;
+ }
+ else
+ {
+ m_flDeployedHeight = m_pOuter->GetViewOffset()[2];
+ }
+}
+
+QAngle CDODPlayerShared::GetDeployedAngles( void ) const
+{
+ return m_vecDeployedAngles;
+}
+
+void CDODPlayerShared::SetDeployedYawLimits( float flLeftYaw, float flRightYaw )
+{
+ m_flDeployedYawLimitLeft = flLeftYaw;
+ m_flDeployedYawLimitRight = -flRightYaw;
+
+ m_vecDeployedAngles = m_pOuter->EyeAngles();
+}
+
+void CDODPlayerShared::ClampDeployedAngles( QAngle *vecTestAngles )
+{
+ Assert( vecTestAngles );
+
+ // Clamp Pitch
+ vecTestAngles->x = clamp( vecTestAngles->x, MAX_DEPLOY_PITCH, MIN_DEPLOY_PITCH );
+
+ // Clamp Yaw - do a bit more work as yaw will wrap around and cause problems
+ float flDeployedYawCenter = GetDeployedAngles().y;
+
+ float flDelta = AngleNormalize( vecTestAngles->y - flDeployedYawCenter );
+
+ if( flDelta < m_flDeployedYawLimitRight )
+ {
+ vecTestAngles->y = flDeployedYawCenter + m_flDeployedYawLimitRight;
+ }
+ else if( flDelta > m_flDeployedYawLimitLeft )
+ {
+ vecTestAngles->y = flDeployedYawCenter + m_flDeployedYawLimitLeft;
+ }
+
+ /*
+ Msg( "delta %.1f ( left %.1f, right %.1f ) ( %.1f -> %.1f )\n",
+ flDelta,
+ flDeployedYawCenter + m_flDeployedYawLimitLeft,
+ flDeployedYawCenter + m_flDeployedYawLimitRight,
+ before,
+ vecTestAngles->y );
+ */
+
+}
+
+float CDODPlayerShared::GetDeployedHeight( void ) const
+{
+ return m_flDeployedHeight;
+}
+
+float CDODPlayerShared::GetSlowedTime( void ) const
+{
+ return m_flSlowedUntilTime;
+}
+
+void CDODPlayerShared::SetSlowedTime( float t )
+{
+ m_flSlowedUntilTime = gpGlobals->curtime + t;
+}
+
+void CDODPlayerShared::StartGoingProne( void )
+{
+ // make the prone sound
+ CPASFilter filter( m_pOuter->GetAbsOrigin() );
+ filter.UsePredictionRules();
+ m_pOuter->EmitSound( filter, m_pOuter->entindex(), "Player.GoProne" );
+
+ // slow to prone speed
+ m_flGoProneTime = gpGlobals->curtime + TIME_TO_PRONE;
+
+ m_flUnProneTime = 0.0f; //reset
+
+ if ( IsSniperZoomed() )
+ ForceUnzoom();
+}
+
+void CDODPlayerShared::StandUpFromProne( void )
+{
+ // make the prone sound
+ CPASFilter filter( m_pOuter->GetAbsOrigin() );
+ filter.UsePredictionRules();
+ m_pOuter->EmitSound( filter, m_pOuter->entindex(), "Player.UnProne" );
+
+ // speed up to target speed
+ m_flUnProneTime = gpGlobals->curtime + TIME_TO_PRONE;
+
+ m_flGoProneTime = 0.0f; //reset
+}
+
+bool CDODPlayerShared::CanChangePosition( void )
+{
+ if ( IsInMGDeploy() )
+ return false;
+
+ if ( IsGettingUpFromProne() )
+ return false;
+
+ if ( IsGoingProne() )
+ return false;
+
+ return true;
+}
+
+void CDODPlayer::UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity )
+{
+ Vector knee;
+ Vector feet;
+ float height;
+ int fLadder;
+
+ if ( m_flStepSoundTime > 0 )
+ {
+ m_flStepSoundTime -= 1000.0f * gpGlobals->frametime;
+ if ( m_flStepSoundTime < 0 )
+ {
+ m_flStepSoundTime = 0;
+ }
+ }
+
+ if ( m_flStepSoundTime > 0 )
+ return;
+
+ if ( GetFlags() & (FL_FROZEN|FL_ATCONTROLS))
+ return;
+
+ if ( GetMoveType() == MOVETYPE_NOCLIP || GetMoveType() == MOVETYPE_OBSERVER )
+ return;
+
+ if ( !sv_footsteps.GetFloat() )
+ return;
+
+ float speed = VectorLength( vecVelocity );
+ float groundspeed = Vector2DLength( vecVelocity.AsVector2D() );
+
+ // determine if we are on a ladder
+ fLadder = ( GetMoveType() == MOVETYPE_LADDER );
+
+ float flDuck;
+
+ if ( ( GetFlags() & FL_DUCKING) || fLadder )
+ {
+ flDuck = 100;
+ }
+ else
+ {
+ flDuck = 0;
+ }
+
+ static float flMinProneSpeed = 10.0f;
+ static float flMinSpeed = 70.0f;
+ static float flRunSpeed = 110.0f;
+
+ bool onground = ( GetFlags() & FL_ONGROUND );
+ bool movingalongground = ( groundspeed > 0.0f );
+ bool moving_fast_enough = ( speed >= flMinSpeed );
+
+ // always play a step sound if we are moving faster than
+
+ // To hear step sounds you must be either on a ladder or moving along the ground AND
+ // You must be moving fast enough
+
+ CheckProneMoveSound( groundspeed, onground );
+
+ if ( !moving_fast_enough || !(fLadder || ( onground && movingalongground )) )
+ {
+ return;
+ }
+
+ bool bWalking = ( speed < flRunSpeed ); // or ducking!
+
+ VectorCopy( vecOrigin, knee );
+ VectorCopy( vecOrigin, feet );
+
+ height = GetPlayerMaxs()[ 2 ] - GetPlayerMins()[ 2 ];
+
+ knee[2] = vecOrigin[2] + 0.2 * height;
+
+ float flVol;
+
+ // find out what we're stepping in or on...
+ if ( fLadder )
+ {
+ psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "ladder" ) );
+ flVol = 1.0;
+ m_flStepSoundTime = 350;
+ }
+ else if ( enginetrace->GetPointContents( knee ) & MASK_WATER )
+ {
+ static int iSkipStep = 0;
+
+ if ( iSkipStep == 0 )
+ {
+ iSkipStep++;
+ return;
+ }
+
+ if ( iSkipStep++ == 3 )
+ {
+ iSkipStep = 0;
+ }
+ psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "wade" ) );
+ flVol = 0.65;
+ m_flStepSoundTime = 600;
+ }
+ else if ( enginetrace->GetPointContents( feet ) & MASK_WATER )
+ {
+ psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "water" ) );
+ flVol = bWalking ? 0.2 : 0.5;
+ m_flStepSoundTime = bWalking ? 400 : 300;
+ }
+ else
+ {
+ if ( !psurface )
+ return;
+
+ if ( bWalking )
+ {
+ m_flStepSoundTime = 400;
+ }
+ else
+ {
+ if ( speed > 200 )
+ {
+ int speeddiff = PLAYER_SPEED_SPRINT - PLAYER_SPEED_RUN;
+ int diff = speed - PLAYER_SPEED_RUN;
+
+ float percent = (float)diff / (float)speeddiff;
+
+ m_flStepSoundTime = 300.0f - 30.0f * percent;
+ }
+ else
+ {
+ m_flStepSoundTime = 400;
+ }
+ }
+
+ switch ( psurface->game.material )
+ {
+ default:
+ case CHAR_TEX_CONCRETE:
+ flVol = bWalking ? 0.2 : 0.5;
+ break;
+
+ case CHAR_TEX_METAL:
+ flVol = bWalking ? 0.2 : 0.5;
+ break;
+
+ case CHAR_TEX_DIRT:
+ flVol = bWalking ? 0.25 : 0.55;
+ break;
+
+ case CHAR_TEX_VENT:
+ flVol = bWalking ? 0.4 : 0.7;
+ break;
+
+ case CHAR_TEX_GRATE:
+ flVol = bWalking ? 0.2 : 0.5;
+ break;
+
+ case CHAR_TEX_TILE:
+ flVol = bWalking ? 0.2 : 0.5;
+ break;
+
+ case CHAR_TEX_SLOSH:
+ flVol = bWalking ? 0.2 : 0.5;
+ break;
+ }
+ }
+
+ m_flStepSoundTime += flDuck; // slower step time if ducking
+
+ if ( GetFlags() & FL_DUCKING )
+ {
+ flVol *= 0.65;
+ }
+
+ // protect us from prediction errors a little bit
+ if ( m_flMinNextStepSoundTime > gpGlobals->curtime )
+ {
+ return;
+ }
+
+ m_flMinNextStepSoundTime = gpGlobals->curtime + 0.1f;
+
+ PlayStepSound( feet, psurface, flVol, false );
+}
+
+void CDODPlayer::CheckProneMoveSound( int groundspeed, bool onground )
+{
+#ifdef CLIENT_DLL
+ bool bShouldPlay = (groundspeed > 10) && (onground == true) && m_Shared.IsProne() && IsAlive();
+
+ if ( m_bPlayingProneMoveSound && !bShouldPlay )
+ {
+ StopSound( "Player.MoveProne" );
+ m_bPlayingProneMoveSound= false;
+ }
+ else if ( !m_bPlayingProneMoveSound && bShouldPlay )
+ {
+ CRecipientFilter filter;
+ filter.AddRecipientsByPAS( WorldSpaceCenter() );
+ EmitSound( filter, entindex(), "Player.MoveProne" );
+
+ m_bPlayingProneMoveSound = true;
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : step -
+// fvol -
+// force - force sound to play
+//-----------------------------------------------------------------------------
+void CDODPlayer::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force )
+{
+ if ( gpGlobals->maxClients > 1 && !sv_footsteps.GetFloat() )
+ return;
+
+#if defined( CLIENT_DLL )
+ // during prediction play footstep sounds only once
+ if ( prediction->InPrediction() && !prediction->IsFirstTimePredicted() )
+ return;
+#endif
+
+ if ( !psurface )
+ return;
+
+ unsigned short stepSoundName = m_Local.m_nStepside ? psurface->sounds.stepleft : psurface->sounds.stepright;
+ m_Local.m_nStepside = !m_Local.m_nStepside;
+
+ if ( !stepSoundName )
+ return;
+
+ IPhysicsSurfaceProps *physprops = MoveHelper( )->GetSurfaceProps();
+ const char *pSoundName = physprops->GetString( stepSoundName );
+ CSoundParameters params;
+
+ // we don't always know the model, so go by team
+ char *pModelNameForGender = DOD_PLAYERMODEL_AXIS_RIFLEMAN;
+
+ if( GetTeamNumber() == TEAM_ALLIES )
+ pModelNameForGender = DOD_PLAYERMODEL_US_RIFLEMAN;
+
+ if ( !CBaseEntity::GetParametersForSound( pSoundName, params, pModelNameForGender ) )
+ return;
+
+ CRecipientFilter filter;
+ filter.AddRecipientsByPAS( vecOrigin );
+
+#ifndef CLIENT_DLL
+ // im MP, server removed all players in origins PVS, these players
+ // generate the footsteps clientside
+ if ( gpGlobals->maxClients > 1 )
+ filter.RemoveRecipientsByPVS( vecOrigin );
+#endif
+
+ EmitSound_t ep;
+ ep.m_nChannel = params.channel;
+ ep.m_pSoundName = params.soundname;
+ ep.m_flVolume = fvol;
+ ep.m_SoundLevel = params.soundlevel;
+ ep.m_nFlags = 0;
+ ep.m_nPitch = params.pitch;
+ ep.m_pOrigin = &vecOrigin;
+
+ EmitSound( filter, entindex(), ep );
+}
+
+Activity CDODPlayer::TranslateActivity( Activity baseAct, bool *pRequired /* = NULL */ )
+{
+ Activity translated = baseAct;
+
+ if ( GetActiveWeapon() )
+ {
+ translated = GetActiveWeapon()->ActivityOverride( baseAct, pRequired );
+ }
+ else if (pRequired)
+ {
+ *pRequired = false;
+ }
+
+ return translated;
+}
+
+void CDODPlayerShared::SetCPIndex( int index )
+{
+#ifdef CLIENT_DLL
+
+ if ( m_pOuter->IsLocalPlayer() )
+ {
+ if ( index == -1 )
+ {
+ // just left an area
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ObjectiveIconShrink" );
+ }
+ else
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ObjectiveIconGrow" );
+ }
+ }
+
+#endif
+
+ m_iCPIndex = index;
+}
+
+void CDODPlayerShared::SetLastViewAnimTime( float flTime )
+{
+ m_flLastViewAnimationTime = flTime;
+}
+
+float CDODPlayerShared::GetLastViewAnimTime( void )
+{
+ return m_flLastViewAnimationTime;
+}
+
+void CDODPlayerShared::ResetViewOffsetAnimation( void )
+{
+ if ( m_pViewOffsetAnim )
+ {
+ //cancel it!
+ m_pViewOffsetAnim->Reset();
+ }
+}
+
+void CDODPlayerShared::ViewOffsetAnimation( Vector vecDest, float flTime, ViewAnimationType type )
+{
+ if ( !m_pViewOffsetAnim )
+ {
+ m_pViewOffsetAnim = CViewOffsetAnimation::CreateViewOffsetAnim( m_pOuter );
+ }
+
+ Assert( m_pViewOffsetAnim );
+
+ if ( m_pViewOffsetAnim )
+ {
+ m_pViewOffsetAnim->StartAnimation( m_pOuter->GetViewOffset(), vecDest, flTime, type );
+ }
+}
+
+void CDODPlayerShared::ViewAnimThink( void )
+{
+ // Check for the flag that will reset our view animations
+ // when the player respawns
+ if ( m_bForceProneChange )
+ {
+ ResetViewOffsetAnimation();
+
+ m_pOuter->SetViewOffset( VEC_VIEW_SCALED( m_pOuter ) );
+
+ m_bForceProneChange = false;
+ }
+
+ if ( m_pViewOffsetAnim )
+ {
+ m_pViewOffsetAnim->Think();
+ }
+}
+
+void CDODPlayerShared::ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs )
+{
+ Vector org = m_pOuter->GetAbsOrigin();
+
+ if ( IsProne() )
+ {
+ static Vector vecProneMin(-44, -44, 0 );
+ static Vector vecProneMax(44, 44, 24 );
+
+ VectorAdd( vecProneMin, org, *pVecWorldMins );
+ VectorAdd( vecProneMax, org, *pVecWorldMaxs );
+ }
+ else
+ {
+ static Vector vecMin(-32, -32, 0 );
+ static Vector vecMax(32, 32, 72 );
+
+ VectorAdd( vecMin, org, *pVecWorldMins );
+ VectorAdd( vecMax, org, *pVecWorldMaxs );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets whether this player is dominating the specified other player
+//-----------------------------------------------------------------------------
+void CDODPlayerShared::SetPlayerDominated( CDODPlayer *pPlayer, bool bDominated )
+{
+ int iPlayerIndex = pPlayer->entindex();
+ m_bPlayerDominated.Set( iPlayerIndex, bDominated );
+ pPlayer->m_Shared.SetPlayerDominatingMe( m_pOuter, bDominated );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets whether this player is being dominated by the other player
+//-----------------------------------------------------------------------------
+void CDODPlayerShared::SetPlayerDominatingMe( CDODPlayer *pPlayer, bool bDominated )
+{
+ int iPlayerIndex = pPlayer->entindex();
+ m_bPlayerDominatingMe.Set( iPlayerIndex, bDominated );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns whether this player is dominating the specified other player
+//-----------------------------------------------------------------------------
+bool CDODPlayerShared::IsPlayerDominated( int iPlayerIndex )
+{
+#ifdef CLIENT_DLL
+ // On the client, we only have data for the local player.
+ // As a result, it's only valid to ask for dominations related to the local player
+ C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
+ if ( !pLocalPlayer )
+ return false;
+
+ Assert( m_pOuter->IsLocalPlayer() || pLocalPlayer->entindex() == iPlayerIndex );
+
+ if ( m_pOuter->IsLocalPlayer() )
+ return m_bPlayerDominated.Get( iPlayerIndex );
+
+ return pLocalPlayer->m_Shared.IsPlayerDominatingMe( m_pOuter->entindex() );
+#else
+ // Server has all the data.
+ return m_bPlayerDominated.Get( iPlayerIndex );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CDODPlayerShared::IsPlayerDominatingMe( int iPlayerIndex )
+{
+ return m_bPlayerDominatingMe.Get( iPlayerIndex );
+}
diff --git a/game/shared/dod/dod_player_shared.h b/game/shared/dod/dod_player_shared.h
new file mode 100644
index 0000000..9d982d3
--- /dev/null
+++ b/game/shared/dod/dod_player_shared.h
@@ -0,0 +1,285 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef DOD_PLAYER_SHARED_H
+#define DOD_PLAYER_SHARED_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "networkvar.h"
+#include "weapon_dodbase.h"
+
+
+#ifdef CLIENT_DLL
+ class C_DODPlayer;
+#else
+ class CDODPlayer;
+#endif
+
+// Entity Messages
+#define DOD_PLAYER_POP_HELMET 1
+#define DOD_PLAYER_REMOVE_DECALS 2
+
+class CViewOffsetAnimation
+{
+public:
+ CViewOffsetAnimation( CBasePlayer *pPlayer )
+ {
+ m_pPlayer = pPlayer;
+ m_vecStart = vec3_origin;
+ m_vecDest = vec3_origin;
+ m_flLength = 0.0;
+ m_flEndTime = 0.0;
+ m_eViewAnimType = VIEW_ANIM_LINEAR_Z_ONLY;
+ m_bActive = false;
+ }
+
+ static CViewOffsetAnimation *CreateViewOffsetAnim( CBasePlayer *pPlayer )
+ {
+ CViewOffsetAnimation *p = new CViewOffsetAnimation( pPlayer );
+
+ Assert( p );
+
+ return p;
+ }
+
+ void StartAnimation( Vector vecStart, Vector vecDest, float flTime, ViewAnimationType type )
+ {
+ m_vecStart = vecStart;
+ m_vecDest = vecDest;
+ m_flLength = flTime;
+ m_flEndTime = gpGlobals->curtime + flTime;
+ m_eViewAnimType = type;
+ m_bActive = true;
+ }
+
+ void Reset( void )
+ {
+ m_bActive = false;
+ }
+
+ void Think( void )
+ {
+ if ( !m_bActive )
+ return;
+
+ if ( IsFinished() )
+ {
+ m_bActive = false;
+ return;
+ }
+
+ float flFraction = ( m_flEndTime - gpGlobals->curtime ) / m_flLength;
+
+ Assert( m_pPlayer );
+
+ if ( m_pPlayer )
+ {
+ Vector vecCurrentView = m_pPlayer->GetViewOffset();
+
+ switch ( m_eViewAnimType )
+ {
+ case VIEW_ANIM_LINEAR_Z_ONLY:
+ vecCurrentView.z = flFraction * m_vecStart.z + ( 1.0 - flFraction ) * m_vecDest.z;
+ break;
+
+ case VIEW_ANIM_SPLINE_Z_ONLY:
+ vecCurrentView.z = SimpleSplineRemapVal( flFraction, 1.0, 0.0, m_vecStart.z, m_vecDest.z );
+ break;
+
+ case VIEW_ANIM_EXPONENTIAL_Z_ONLY:
+ {
+ float flBias = Bias( flFraction, 0.2 );
+ vecCurrentView.z = flBias * m_vecStart.z + ( 1.0 - flBias ) * m_vecDest.z;
+ }
+ break;
+ }
+
+ m_pPlayer->SetViewOffset( vecCurrentView );
+ }
+ }
+
+ bool IsFinished( void )
+ {
+ return ( gpGlobals->curtime > m_flEndTime || m_pPlayer == NULL );
+ }
+
+private:
+ CBasePlayer *m_pPlayer;
+ Vector m_vecStart;
+ Vector m_vecDest;
+ float m_flEndTime;
+ float m_flLength;
+ ViewAnimationType m_eViewAnimType;
+ bool m_bActive;
+};
+
+
+// Data in the DoD player that is accessed by shared code.
+// This data isn't necessarily transmitted between client and server.
+class CDODPlayerShared
+{
+public:
+
+#ifdef CLIENT_DLL
+ friend class C_DODPlayer;
+ typedef C_DODPlayer OuterClass;
+ DECLARE_PREDICTABLE();
+#else
+ friend class CDODPlayer;
+ typedef CDODPlayer OuterClass;
+#endif
+
+ DECLARE_EMBEDDED_NETWORKVAR()
+ DECLARE_CLASS_NOBASE( CDODPlayerShared );
+
+
+ CDODPlayerShared();
+ ~CDODPlayerShared();
+
+ void SetStamina( float stamina );
+ float GetStamina( void ) { return m_flStamina; }
+
+ void Init( OuterClass *pOuter );
+
+ bool IsProne() const;
+ bool IsGettingUpFromProne() const;
+ bool IsGoingProne() const;
+ void SetProne( bool bProne, bool bNoAnimation = false );
+
+ bool IsBazookaDeployed( void ) const;
+ bool IsBazookaOnlyDeployed( void ) const;
+ bool IsSniperZoomed( void ) const;
+ bool IsInMGDeploy( void ) const;
+ bool IsProneDeployed( void ) const;
+ bool IsSandbagDeployed( void ) const;
+ bool IsDucking( void ) const;
+
+ void SetDesiredPlayerClass( int playerclass );
+ int DesiredPlayerClass( void );
+
+ void SetPlayerClass( int playerclass );
+ int PlayerClass( void );
+
+ CWeaponDODBase* GetActiveDODWeapon() const;
+
+ void SetDeployed( bool bDeployed, float flHeight = -1 );
+
+ QAngle GetDeployedAngles( void ) const;
+ float GetDeployedHeight( void ) const;
+
+ void SetDeployedYawLimits( float flLeftYaw, float flRightYaw );
+ void ClampDeployedAngles( QAngle *vecTestAngles );
+
+ void SetSlowedTime( float t );
+ float GetSlowedTime( void ) const;
+
+ void StartGoingProne( void );
+ void StandUpFromProne( void );
+
+ bool CanChangePosition( void );
+
+ bool IsJumping( void ) { return m_bJumping; }
+ void SetJumping( bool bJumping );
+
+ bool IsSprinting( void ) { return m_bIsSprinting; }
+
+ void ForceUnzoom( void );
+
+ void SetSprinting( bool bSprinting );
+ void StartSprinting( void );
+ void StopSprinting( void );
+
+ void SetCPIndex( int index );
+ int GetCPIndex( void ) { return m_iCPIndex; }
+
+ void SetLastViewAnimTime( float flTime );
+ float GetLastViewAnimTime( void );
+
+ void ViewAnimThink( void );
+
+ void ResetViewOffsetAnimation( void );
+ void ViewOffsetAnimation( Vector vecDest, float flTime, ViewAnimationType type );
+
+ void ResetSprintPenalty( void );
+
+ void SetPlanting( bool bPlanting )
+ {
+ m_bPlanting = bPlanting;
+ }
+
+ bool IsPlanting( void ) { return m_bPlanting; }
+
+ void SetDefusing( bool bDefusing )
+ {
+ m_bDefusing = bDefusing;
+ }
+
+ bool IsDefusing( void ) { return m_bDefusing; }
+
+ void ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
+
+ void SetPlayerDominated( CDODPlayer *pPlayer, bool bDominated );
+ bool IsPlayerDominated( int iPlayerIndex );
+ bool IsPlayerDominatingMe( int iPlayerIndex );
+ void SetPlayerDominatingMe( CDODPlayer *pPlayer, bool bDominated );
+
+private:
+
+ CNetworkVar( bool, m_bProne );
+
+ CNetworkVar( int, m_iPlayerClass );
+ CNetworkVar( int, m_iDesiredPlayerClass );
+
+ CNetworkVar( float, m_flStamina );
+
+ CNetworkVar( float, m_flSlowedUntilTime );
+
+ CNetworkVar( bool, m_bIsSprinting );
+
+ CNetworkVar( float, m_flDeployedYawLimitLeft );
+ CNetworkVar( float, m_flDeployedYawLimitRight );
+
+ CNetworkVar( bool, m_bPlanting );
+ CNetworkVar( bool, m_bDefusing );
+
+ bool m_bGaveSprintPenalty;
+
+public:
+ float m_flNextProneCheck; // Prevent it switching their prone state constantly.
+
+ QAngle m_vecDeployedAngles;
+ //float m_flDeployedHeight;
+ CNetworkVar( float, m_flDeployedHeight );
+
+ CNetworkVar( float, m_flUnProneTime );
+ CNetworkVar( float, m_flGoProneTime );
+
+ CNetworkVar( float, m_flDeployChangeTime );
+
+ CNetworkVar( bool, m_bForceProneChange );
+
+ CNetworkVar( int, m_iCPIndex );
+
+ bool m_bJumping;
+
+ float m_flLastViewAnimationTime;
+
+ CViewOffsetAnimation *m_pViewOffsetAnim;
+
+ CNetworkArray( bool, m_bPlayerDominated, MAX_PLAYERS+1 ); // array of state per other player whether player is dominating other players
+ CNetworkArray( bool, m_bPlayerDominatingMe, MAX_PLAYERS+1 ); // array of state per other player whether other players are dominating this player
+
+private:
+
+ OuterClass *m_pOuter;
+};
+
+
+
+#endif // DOD_PLAYER_SHARED_H
diff --git a/game/shared/dod/dod_playeranimstate.cpp b/game/shared/dod/dod_playeranimstate.cpp
new file mode 100644
index 0000000..9570ff9
--- /dev/null
+++ b/game/shared/dod/dod_playeranimstate.cpp
@@ -0,0 +1,1454 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "dod_playeranimstate.h"
+#include "base_playeranimstate.h"
+#include "tier0/vprof.h"
+#include "animation.h"
+#include "studio.h"
+#include "apparent_velocity_helper.h"
+#include "utldict.h"
+#include "weapon_dodbase.h"
+#include "dod_shareddefs.h"
+
+#ifdef CLIENT_DLL
+ #include "c_dod_player.h"
+ #include "engine/ivdebugoverlay.h"
+ #include "filesystem.h"
+
+ ConVar anim_showmainactivity( "anim_showmainactivity", "0", FCVAR_CHEAT, "Show the idle, walk, run, and/or sprint activities." );
+#else
+ #include "dod_player.h"
+#endif
+
+ConVar anim_showstate( "anim_showstate", "-1", FCVAR_CHEAT | FCVAR_REPLICATED, "Show the (client) animation state for the specified entity (-1 for none)." );
+ConVar anim_showstatelog( "anim_showstatelog", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "1 to output anim_showstate to Msg(). 2 to store in AnimState.log. 3 for both." );
+ConVar dod_bodyheightoffset( "dod_bodyheightoffset", "4", FCVAR_CHEAT | FCVAR_REPLICATED, "Deploy height offset." );
+
+#define ANIMPART_STAND "stand"
+#define ANIMPART_PRONE "prone"
+#define ANIMPART_CROUCH "crouch"
+#define ANIMPART_SPRINT "sprint"
+#define ANIMPART_SANDBAG "sandbag"
+#define ANIMPART_BIPOD "bipod"
+
+// When moving this fast, he plays run anim.
+#define ARBITRARY_RUN_SPEED 300.0f
+#define DOD_BODYYAW_RATE 720.0f
+
+#define DOD_WALK_SPEED 60.0f
+#define DOD_RUN_SPEED 120.0f
+#define DOD_SPRINT_SPEED 260.0f
+
+class CDODPlayerAnimState : public CBasePlayerAnimState, public IDODPlayerAnimState
+{
+public:
+
+ DECLARE_CLASS( CDODPlayerAnimState, CBasePlayerAnimState );
+ friend IDODPlayerAnimState* CreatePlayerAnimState( CDODPlayer *pPlayer );
+
+ CDODPlayerAnimState();
+
+ virtual void ShowDebugInfo( void );
+
+ // This is called by both the client and the server in the same way to trigger events for
+ // players firing, jumping, throwing grenades, etc.
+ virtual void DoAnimationEvent( PlayerAnimEvent_t event, int nData );
+ virtual void ClearAnimationState();
+ virtual Activity CalcMainActivity();
+ virtual void Update( float eyeYaw, float eyePitch );
+
+ virtual void DebugShowAnimState( int iStartLine );
+
+ virtual int CalcAimLayerSequence( float *flCyle, float *flAimSequenceWeight, bool bForceIdle ) { return 0; }
+
+ virtual float GetCurrentMaxGroundSpeed();
+ virtual void ComputeSequences( CStudioHdr *pStudioHdr );
+ virtual void ClearAnimationLayers();
+
+ virtual void RestartMainSequence();
+ virtual float CalcMovementPlaybackRate( bool *bIsMoving );
+
+ Activity TranslateActivity( Activity actDesired );
+ void CancelGestures( void );
+
+protected:
+
+ // Pose paramters.
+ bool SetupPoseParameters( CStudioHdr *pStudioHdr );
+ virtual void ComputePoseParam_MoveYaw( CStudioHdr *pStudioHdr );
+ virtual void ComputePoseParam_AimPitch( CStudioHdr *pStudioHdr );
+ virtual void ComputePoseParam_AimYaw( CStudioHdr *pStudioHdr );
+ void ComputePoseParam_BodyHeight( CStudioHdr *pStudioHdr );
+ virtual void EstimateYaw( void );
+ void ConvergeYawAngles( float flGoalYaw, float flYawRate, float flDeltaTime, float &flCurrentYaw );
+
+ void ComputeFireSequence();
+ void ComputeDeployedSequence();
+
+ void ComputeGestureSequence( CStudioHdr *pStudioHdr );
+
+ void RestartGesture( int iGestureType, Activity act, bool bAutoKill = true );
+
+ void UpdateLayerSequenceGeneric( CStudioHdr *pStudioHdr, int iLayer, bool &bEnabled, float &flCurCycle, int &iSequence, bool bWaitAtEnd, float flWeight = 1.0 );
+
+ void DebugShowAnimStateForPlayer( bool bIsServer );
+ void DebugShowEyeYaw( void );
+
+// Client specific.
+#ifdef CLIENT_DLL
+
+ // Debug.
+ void DebugShowActivity( Activity activity );
+
+#endif
+
+private:
+
+ void InitDOD( CDODPlayer *pPlayer );
+
+ bool HandleJumping( Activity *idealActivity );
+ bool HandleProne( Activity *idealActivity );
+ bool HandleProneDown( CDODPlayer *pPlayer, Activity *idealActivity );
+ bool HandleProneUp( CDODPlayer *pPlayer, Activity *idealActivity );
+ bool HandleDucked( Activity *idealActivity );
+
+ bool IsGettingDown( CDODPlayer *pPlayer );
+ bool IsGettingUp( CDODPlayer *pPlayer );
+
+ CDODPlayer* GetOuterDOD() const;
+
+ bool IsPlayingGesture( int type )
+ {
+ return ( m_bPlayingGesture && m_iGestureType == type );
+ }
+
+private:
+ // Current state variables.
+ bool m_bJumping; // Set on a jump event.
+ float m_flJumpStartTime;
+ bool m_bFirstJumpFrame;
+
+ // These control the prone state _achine.
+ bool m_bGettingDown;
+ bool m_bGettingUp;
+ bool m_bWasGoingProne;
+ bool m_bWasGettingUp;
+
+ // The single Gesture layer
+ bool m_bPlayingGesture;
+ bool m_bAutokillGesture;
+ int m_iGestureSequence;
+ float m_flGestureCycle;
+
+ int m_iGestureType;
+
+ enum
+ {
+ GESTURE_NONE = -1,
+ GESTURE_ATTACK1 = 0,
+ GESTURE_ATTACK2,
+ GESTURE_RELOAD,
+ GESTURE_HAND_SIGNAL,
+ GESTURE_FIDGET,
+ GESTURE_PLANT,
+ GESTURE_DEFUSE,
+ };
+
+ // Pose parameters.
+ bool m_bPoseParameterInit;
+ float m_flEstimateYaw;
+ float m_flEstimateVelocity;
+ float m_flLastAimPitch;
+ float m_flLastAimYaw;
+ float m_flLastBodyHeight;
+ float m_flLastAimTurnTime;
+ Vector2D m_vecLastMoveYaw;
+ int m_iMoveX;
+ int m_iMoveY;
+ int m_iAimYaw;
+ int m_iAimPitch;
+ int m_iBodyHeight;
+
+ float m_flFireIdleTime; // Time that we drop our gun
+
+ bool m_bLastDeployState; // true = last was deployed, false = last was not deployed
+
+ DODWeaponID m_iLastWeaponID; // remember the weapon we were last using
+
+ // Our DOD player pointer.
+ CDODPlayer *m_pOuterDOD;
+};
+
+
+IDODPlayerAnimState* CreatePlayerAnimState( CDODPlayer *pPlayer )
+{
+ CDODPlayerAnimState *pState = new CDODPlayerAnimState;
+ pState->InitDOD( pPlayer );
+ return pState;
+}
+
+
+// -------------------------------------------------------------------------------- //
+// CDODPlayerAnimState implementation.
+// -------------------------------------------------------------------------------- //
+
+CDODPlayerAnimState::CDODPlayerAnimState()
+{
+ m_bGettingDown = false;
+ m_bGettingUp = false;
+ m_bWasGoingProne = false;
+ m_bWasGettingUp = false;
+
+ m_pOuterDOD = NULL;
+
+ m_bPoseParameterInit = false;
+ m_flEstimateYaw = 0.0f;
+ m_flLastAimPitch = 0.0f;
+ m_flLastAimYaw = 0.0f;
+ m_flLastBodyHeight = 0.0f;
+ m_flLastAimTurnTime = 0.0f;
+ m_vecLastMoveYaw.Init();
+ m_iMoveX = -1;
+ m_iMoveY = -1;
+ m_iAimYaw = -1;
+ m_iAimPitch = -1;
+ m_iBodyHeight = -1;
+}
+
+void CDODPlayerAnimState::InitDOD( CDODPlayer *pPlayer )
+{
+ m_pOuterDOD = pPlayer;
+
+ CModAnimConfig config;
+ config.m_flMaxBodyYawDegrees = 45;
+ config.m_LegAnimType = LEGANIM_GOLDSRC;
+ config.m_bUseAimSequences = false;
+
+ BaseClass::Init( pPlayer, config );
+}
+
+
+void CDODPlayerAnimState::ClearAnimationState()
+{
+ m_bJumping = false;
+ m_flFireIdleTime = 0;
+ m_bLastDeployState = false;
+ m_iLastWeaponID = WEAPON_NONE;
+ CancelGestures();
+ BaseClass::ClearAnimationState();
+}
+
+void CDODPlayerAnimState::DoAnimationEvent( PlayerAnimEvent_t event, int nData )
+{
+ if ( event == PLAYERANIMEVENT_FIRE_GUN )
+ {
+ RestartGesture( GESTURE_ATTACK1, ACT_RANGE_ATTACK1, false );
+
+ if( GetOuterDOD()->m_Shared.IsBazookaDeployed() )
+ {
+ m_flFireIdleTime = gpGlobals->curtime + 0.1; // don't hold this pose after firing
+ }
+ else
+ {
+ // hold last frame of fire pose for 2 seconds ( if we are moving )
+ m_flFireIdleTime = gpGlobals->curtime + 2;
+ }
+ }
+ if ( event == PLAYERANIMEVENT_SECONDARY_ATTACK )
+ {
+ CancelGestures();
+ RestartGesture( GESTURE_ATTACK2, ACT_RANGE_ATTACK2 );
+ }
+ else if ( event == PLAYERANIMEVENT_RELOAD )
+ {
+ CancelGestures();
+ RestartGesture( GESTURE_RELOAD, ACT_RELOAD );
+ }
+ else if ( event == PLAYERANIMEVENT_THROW_GRENADE )
+ {
+ CancelGestures();
+ RestartGesture( GESTURE_ATTACK1, ACT_RANGE_ATTACK1 );
+ }
+ else if ( event == PLAYERANIMEVENT_ROLL_GRENADE )
+ {
+ CancelGestures();
+ RestartGesture( GESTURE_ATTACK2, ACT_RANGE_ATTACK2 );
+ }
+ else if ( event == PLAYERANIMEVENT_JUMP )
+ {
+ // Play the jump animation.
+ m_bJumping = true;
+ m_bFirstJumpFrame = true;
+ RestartMainSequence();
+ m_flJumpStartTime = gpGlobals->curtime;
+ }
+ else if ( event == PLAYERANIMEVENT_HANDSIGNAL )
+ {
+ CDODPlayer *pPlayer = GetOuterDOD();
+ if ( pPlayer && !( pPlayer->m_Shared.IsBazookaDeployed() || pPlayer->m_Shared.IsProne() || pPlayer->m_Shared.IsProneDeployed() || pPlayer->m_Shared.IsSniperZoomed() || pPlayer->m_Shared.IsSandbagDeployed() ) )
+ {
+ CancelGestures();
+ RestartGesture( GESTURE_HAND_SIGNAL, ACT_DOD_HS_IDLE );
+ }
+ }
+ else if ( event == PLAYERANIMEVENT_PLANT_TNT )
+ {
+ CancelGestures();
+ RestartGesture( GESTURE_PLANT, ACT_DOD_PLANT_TNT );
+ }
+ else if ( event == PLAYERANIMEVENT_DEFUSE_TNT )
+ {
+ CancelGestures();
+ RestartGesture( GESTURE_DEFUSE, ACT_DOD_DEFUSE_TNT );
+ }
+}
+
+void CDODPlayerAnimState::ShowDebugInfo( void )
+{
+ if ( anim_showstate.GetInt() == m_pOuter->entindex() )
+ {
+ DebugShowAnimStateForPlayer( m_pOuter->IsServer() );
+ }
+}
+
+
+void CDODPlayerAnimState::RestartMainSequence()
+{
+ CancelGestures();
+
+ BaseClass::RestartMainSequence();
+}
+
+bool CDODPlayerAnimState::HandleJumping( Activity *idealActivity )
+{
+ if ( m_bJumping )
+ {
+ if ( m_bFirstJumpFrame )
+ {
+ m_bFirstJumpFrame = false;
+ RestartMainSequence(); // Reset the animation.
+ }
+
+ // Don't check if he's on the ground for a sec.. sometimes the client still has the
+ // on-ground flag set right when the message comes in.
+ if ( gpGlobals->curtime - m_flJumpStartTime > 0.2f )
+ {
+ if ( m_pOuter->GetFlags() & FL_ONGROUND )
+ {
+ m_bJumping = false;
+ RestartMainSequence();
+ }
+ }
+ }
+ if ( m_bJumping )
+ {
+ *idealActivity = ACT_HOP;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle the prone up animation.
+//-----------------------------------------------------------------------------
+bool CDODPlayerAnimState::HandleProneDown( CDODPlayer *pPlayer, Activity *idealActivity )
+{
+ if ( ( pPlayer->GetCycle() > 0.99f ) || ( pPlayer->m_Shared.IsProne() ) )
+ {
+ *idealActivity = ACT_PRONE_IDLE;
+ if ( GetOuterXYSpeed() > MOVING_MINIMUM_SPEED )
+ {
+ *idealActivity = ACT_PRONE_FORWARD;
+ }
+ RestartMainSequence();
+
+ m_bGettingDown = false;
+ }
+ else
+ {
+ *idealActivity = ACT_GET_DOWN_STAND;
+ if ( pPlayer->GetFlags() & FL_DUCKING )
+ {
+ *idealActivity = ACT_GET_DOWN_CROUCH;
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle the prone up animation.
+//-----------------------------------------------------------------------------
+bool CDODPlayerAnimState::HandleProneUp( CDODPlayer *pPlayer, Activity *idealActivity )
+{
+ if ( ( m_pOuter->GetCycle() > 0.99f ) || ( !pPlayer->m_Shared.IsGettingUpFromProne() ) )
+ {
+ m_bGettingUp = false;
+ RestartMainSequence();
+
+ return false;
+ }
+
+ *idealActivity = ACT_GET_UP_STAND;
+ if ( pPlayer->GetFlags() & FL_DUCKING )
+ {
+ *idealActivity = ACT_GET_UP_CROUCH;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle the prone animations.
+//-----------------------------------------------------------------------------
+bool CDODPlayerAnimState::HandleProne( Activity *idealActivity )
+{
+ // Get the player.
+ CDODPlayer *pPlayer = GetOuterDOD();
+ if ( !pPlayer )
+ return false;
+
+ // Find the leading edge on going prone.
+ bool bChange = pPlayer->m_Shared.IsGoingProne() && !m_bWasGoingProne;
+ m_bWasGoingProne = pPlayer->m_Shared.IsGoingProne();
+ if ( bChange )
+ {
+ m_bGettingDown = true;
+ RestartMainSequence();
+ }
+
+ // Find the leading edge on getting up.
+ bChange = pPlayer->m_Shared.IsGettingUpFromProne() && !m_bWasGettingUp;
+ m_bWasGettingUp = pPlayer->m_Shared.IsGettingUpFromProne();
+ if ( bChange )
+ {
+ m_bGettingUp = true;
+ RestartMainSequence();
+ }
+
+ // Handle the transitions.
+ if ( m_bGettingDown )
+ {
+ return HandleProneDown( pPlayer, idealActivity );
+ }
+ else if ( m_bGettingUp )
+ {
+ return HandleProneUp( pPlayer, idealActivity );
+ }
+
+ // Handle the prone state.
+ if ( pPlayer->m_Shared.IsProne() )
+ {
+ *idealActivity = ACT_PRONE_IDLE;
+ if ( GetOuterXYSpeed() > MOVING_MINIMUM_SPEED )
+ {
+ *idealActivity = ACT_PRONE_FORWARD;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool CDODPlayerAnimState::HandleDucked( Activity *idealActivity )
+{
+ if ( m_pOuter->GetFlags() & FL_DUCKING )
+ {
+ if ( GetOuterXYSpeed() > MOVING_MINIMUM_SPEED )
+ *idealActivity = ACT_RUN_CROUCH;
+ else
+ *idealActivity = ACT_CROUCHIDLE;
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+Activity CDODPlayerAnimState::CalcMainActivity()
+{
+ Activity idealActivity = ACT_IDLE;
+
+ float flSpeed = GetOuterXYSpeed();
+
+ if ( HandleJumping( &idealActivity ) ||
+ HandleProne( &idealActivity ) ||
+ HandleDucked( &idealActivity ) )
+ {
+ // intentionally blank
+ }
+ else
+ {
+ if ( flSpeed > MOVING_MINIMUM_SPEED )
+ {
+ if( flSpeed >= DOD_SPRINT_SPEED )
+ {
+ idealActivity = ACT_SPRINT;
+
+ // If we sprint, cancel the fire idle time
+ CancelGestures();
+ }
+ else if( flSpeed >= DOD_WALK_SPEED )
+ idealActivity = ACT_RUN;
+ else
+ idealActivity = ACT_WALK;
+ }
+ }
+
+ // Shouldn't be here but we need to ship - bazooka deployed reload/running check.
+ if ( IsPlayingGesture( GESTURE_RELOAD ) )
+ {
+ if ( flSpeed >= DOD_RUN_SPEED && m_pOuterDOD->m_Shared.IsBazookaOnlyDeployed() )
+ {
+ CancelGestures();
+ }
+ }
+
+ ShowDebugInfo();
+
+ // Client specific.
+#ifdef CLIENT_DLL
+
+ if ( anim_showmainactivity.GetBool() )
+ {
+ DebugShowActivity( idealActivity );
+ }
+
+#endif
+
+ return idealActivity;
+}
+
+void CDODPlayerAnimState::CancelGestures( void )
+{
+ m_bPlayingGesture = false;
+ m_iGestureType = GESTURE_NONE;
+
+#ifdef CLIENT_DLL
+ m_iGestureSequence = -1;
+#else
+ m_pOuter->RemoveAllGestures();
+#endif
+}
+
+void CDODPlayerAnimState::RestartGesture( int iGestureType, Activity act, bool bAutoKill /* = true */ )
+{
+ Activity idealActivity = TranslateActivity( act );
+ m_bPlayingGesture = true;
+ m_iGestureType = iGestureType;
+
+#ifdef CLIENT_DLL
+ m_iGestureSequence = m_pOuter->SelectWeightedSequence( idealActivity );
+
+ if( m_iGestureSequence == -1 )
+ {
+ m_bPlayingGesture = false;
+ }
+
+ m_flGestureCycle = 0.0f;
+ m_bAutokillGesture = bAutoKill;
+#else
+ m_pOuterDOD->RestartGesture( idealActivity, true, bAutoKill );
+#endif
+}
+
+Activity CDODPlayerAnimState::TranslateActivity( Activity actDesired )
+{
+ Activity idealActivity = actDesired;
+
+ if ( m_pOuterDOD->m_Shared.IsSandbagDeployed() )
+ {
+ switch( idealActivity )
+ {
+ case ACT_IDLE:
+ idealActivity = ACT_DOD_DEPLOYED;
+ break;
+ case ACT_RANGE_ATTACK1:
+ idealActivity = ACT_DOD_PRIMARYATTACK_DEPLOYED;
+ break;
+ case ACT_RELOAD:
+ idealActivity = ACT_DOD_RELOAD_DEPLOYED;
+ break;
+ default:
+ break;
+ }
+ }
+ else if ( m_pOuterDOD->m_Shared.IsProneDeployed() )
+ {
+ switch( idealActivity )
+ {
+ case ACT_PRONE_IDLE:
+ idealActivity = ACT_DOD_PRONE_DEPLOYED;
+ break;
+ case ACT_RANGE_ATTACK1:
+ idealActivity = ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED;
+ break;
+ case ACT_RELOAD:
+ idealActivity = ACT_DOD_RELOAD_PRONE_DEPLOYED;
+ break;
+ default:
+ break;
+ }
+ }
+ else if ( m_pOuterDOD->m_Shared.IsSniperZoomed() || m_pOuterDOD->m_Shared.IsBazookaDeployed() )
+ {
+ switch( idealActivity )
+ {
+ case ACT_IDLE:
+ idealActivity = ACT_DOD_IDLE_ZOOMED;
+ break;
+ case ACT_WALK:
+ idealActivity = ACT_DOD_WALK_ZOOMED;
+ break;
+ case ACT_CROUCHIDLE:
+ idealActivity = ACT_DOD_CROUCH_ZOOMED;
+ break;
+ case ACT_RUN_CROUCH:
+ idealActivity = ACT_DOD_CROUCHWALK_ZOOMED;
+ break;
+ case ACT_PRONE_IDLE:
+ idealActivity = ACT_DOD_PRONE_ZOOMED;
+ break;
+ case ACT_PRONE_FORWARD:
+ idealActivity = ACT_DOD_PRONE_FORWARD_ZOOMED;
+ break;
+ case ACT_RANGE_ATTACK1:
+ if ( m_pOuterDOD->m_Shared.IsSniperZoomed() )
+ {
+ if( m_pOuterDOD->m_Shared.IsProne() )
+ idealActivity = ACT_DOD_PRIMARYATTACK_PRONE;
+ }
+ break;
+ case ACT_RELOAD:
+ if ( m_pOuterDOD->m_Shared.IsBazookaDeployed() )
+ {
+ if( m_pOuterDOD->m_Shared.IsProne() )
+ {
+ idealActivity = ACT_DOD_RELOAD_PRONE_DEPLOYED;
+ }
+ else
+ {
+ idealActivity = ACT_DOD_RELOAD_DEPLOYED;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else if ( m_pOuterDOD->m_Shared.IsProne() )
+ {
+ // translate prone shooting, reload, handsignal
+
+ switch( idealActivity )
+ {
+ case ACT_RANGE_ATTACK1:
+ idealActivity = ACT_DOD_PRIMARYATTACK_PRONE;
+ break;
+ case ACT_RANGE_ATTACK2:
+ idealActivity = ACT_DOD_SECONDARYATTACK_PRONE;
+ break;
+ case ACT_RELOAD:
+ idealActivity = ACT_DOD_RELOAD_PRONE;
+ break;
+ default:
+ break;
+ }
+ }
+ else if ( m_pOuter->GetFlags() & FL_DUCKING )
+ {
+ switch( idealActivity )
+ {
+ case ACT_RANGE_ATTACK1:
+ idealActivity = ACT_DOD_PRIMARYATTACK_CROUCH;
+ break;
+ case ACT_RANGE_ATTACK2:
+ idealActivity = ACT_DOD_SECONDARYATTACK_CROUCH;
+ break;
+ case ACT_DOD_HS_IDLE:
+ idealActivity = ACT_DOD_HS_CROUCH;
+ break;
+ }
+ }
+
+ // Are our guns at fire or rest?
+ if ( m_flFireIdleTime > gpGlobals->curtime )
+ {
+ switch( idealActivity )
+ {
+ case ACT_IDLE: idealActivity = ACT_DOD_STAND_AIM; break;
+ case ACT_CROUCHIDLE: idealActivity = ACT_DOD_CROUCH_AIM; break;
+ case ACT_RUN_CROUCH: idealActivity = ACT_DOD_CROUCHWALK_AIM; break;
+ case ACT_WALK: idealActivity = ACT_DOD_WALK_AIM; break;
+ case ACT_RUN: idealActivity = ACT_DOD_RUN_AIM; break;
+ default: break;
+ }
+ }
+ else
+ {
+ switch( idealActivity )
+ {
+ case ACT_IDLE: idealActivity = ACT_DOD_STAND_IDLE; break;
+ case ACT_CROUCHIDLE: idealActivity = ACT_DOD_CROUCH_IDLE; break;
+ case ACT_RUN_CROUCH: idealActivity = ACT_DOD_CROUCHWALK_IDLE; break;
+ case ACT_WALK: idealActivity = ACT_DOD_WALK_IDLE; break;
+ case ACT_RUN: idealActivity = ACT_DOD_RUN_IDLE; break;
+ default: break;
+ }
+ }
+
+ return m_pOuterDOD->TranslateActivity( idealActivity );
+}
+
+CDODPlayer* CDODPlayerAnimState::GetOuterDOD() const
+{
+ return m_pOuterDOD;
+}
+
+float CDODPlayerAnimState::GetCurrentMaxGroundSpeed()
+{
+ return PLAYER_SPEED_SPRINT;
+}
+
+float CDODPlayerAnimState::CalcMovementPlaybackRate( bool *bIsMoving )
+{
+ if( ( GetCurrentMainSequenceActivity() == ACT_GET_UP_STAND ) || ( GetCurrentMainSequenceActivity() == ACT_GET_DOWN_STAND ) ||
+ ( GetCurrentMainSequenceActivity() == ACT_GET_UP_CROUCH ) || ( GetCurrentMainSequenceActivity() == ACT_GET_DOWN_CROUCH ) )
+ {
+ // We don't want to change the playback speed of these, even if we move.
+ *bIsMoving = false;
+ return 1.0;
+ }
+
+ // it would be a good idea to ramp up from 0.5 to 1.0 as they go from stop to moveing, it looks more natural.
+ *bIsMoving = true;
+ return 1.0;
+}
+
+void CDODPlayerAnimState::DebugShowAnimState( int iStartLine )
+{
+#ifdef CLIENT_DLL
+ engine->Con_NPrintf( iStartLine++, "getting down: %s\n", m_bGettingDown ? "yes" : "no" );
+ engine->Con_NPrintf( iStartLine++, "getting up: %s\n", m_bGettingUp ? "yes" : "no" );
+#endif
+
+ BaseClass::DebugShowAnimState( iStartLine );
+}
+
+void CDODPlayerAnimState::ComputeSequences( CStudioHdr *pStudioHdr )
+{
+ // Reset some things if we're changed weapons
+ // do this before ComputeSequences
+ CWeaponDODBase *pWeapon = GetOuterDOD()->m_Shared.GetActiveDODWeapon();
+ if ( pWeapon )
+ {
+ if( pWeapon->GetWeaponID() != m_iLastWeaponID )
+ {
+ CancelGestures();
+ m_iLastWeaponID = pWeapon->GetWeaponID();
+ m_flFireIdleTime = 0;
+ }
+ }
+
+ BaseClass::ComputeSequences( pStudioHdr );
+
+ if( !m_bGettingDown && !m_bGettingUp )
+ {
+ ComputeFireSequence();
+
+#ifdef CLIENT_DLL
+
+ ComputeGestureSequence( pStudioHdr );
+
+ // get the weapon's swap criteria ( reload? attack? deployed? deployed reload? )
+ // and determine whether we should use alt model or not
+
+ CWeaponDODBase *pWeapon = GetOuterDOD()->m_Shared.GetActiveDODWeapon();
+ if ( pWeapon )
+ {
+ int iCurrentState = ALTWPN_CRITERIA_NONE;
+
+ if( m_bPlayingGesture && m_iGestureType == GESTURE_ATTACK1 )
+ iCurrentState |= ALTWPN_CRITERIA_FIRING;
+
+ else if( m_bPlayingGesture && m_iGestureType == GESTURE_RELOAD )
+ iCurrentState |= ALTWPN_CRITERIA_RELOADING;
+
+ if( m_pOuterDOD->m_Shared.IsProne() )
+ iCurrentState |= ALTWPN_CRITERIA_PRONE;
+
+ // always use default model while proning or hand signal
+ if( !IsPlayingGesture( GESTURE_HAND_SIGNAL ) &&
+ !IsPlayingGesture( GESTURE_FIDGET ) &&
+ !m_bGettingDown &&
+ !m_bGettingUp )
+ {
+ pWeapon->CheckForAltWeapon( iCurrentState );
+ }
+ else
+ {
+ pWeapon->SetUseAltModel( false );
+ }
+ }
+#endif
+ }
+}
+
+#define GESTURE_LAYER AIMSEQUENCE_LAYER
+#define NUM_LAYERS_WANTED (GESTURE_LAYER + 1)
+
+void CDODPlayerAnimState::ClearAnimationLayers()
+{
+ if ( !m_pOuter )
+ return;
+
+ m_pOuter->SetNumAnimOverlays( NUM_LAYERS_WANTED );
+ for ( int i=0; i < m_pOuter->GetNumAnimOverlays(); i++ )
+ {
+ m_pOuter->GetAnimOverlay( i )->SetOrder( CBaseAnimatingOverlay::MAX_OVERLAYS );
+ }
+}
+
+void CDODPlayerAnimState::ComputeFireSequence( void )
+{
+ // Hold the shoot pose for a time after firing, unless we stand still
+ if( m_flFireIdleTime < gpGlobals->curtime &&
+ IsPlayingGesture( GESTURE_ATTACK1 ) &&
+ GetOuterXYSpeed() > MOVING_MINIMUM_SPEED )
+ {
+ CancelGestures();
+ }
+
+ if( GetOuterDOD()->m_Shared.IsInMGDeploy() != m_bLastDeployState )
+ {
+ CancelGestures();
+
+ m_bLastDeployState = GetOuterDOD()->m_Shared.IsInMGDeploy();
+ }
+}
+
+void CDODPlayerAnimState::ComputeGestureSequence( CStudioHdr *pStudioHdr )
+{
+ UpdateLayerSequenceGeneric( pStudioHdr, GESTURE_LAYER, m_bPlayingGesture, m_flGestureCycle, m_iGestureSequence, !m_bAutokillGesture );
+}
+
+void CDODPlayerAnimState::UpdateLayerSequenceGeneric( CStudioHdr *pStudioHdr, int iLayer, bool &bEnabled, float &flCurCycle, int &iSequence, bool bWaitAtEnd, float flWeight /* = 1.0 */ )
+{
+ if ( !bEnabled )
+ return;
+
+ if( flCurCycle > 1.0 )
+ flCurCycle = 1.0;
+
+ // Increment the fire sequence's cycle.
+ flCurCycle += m_pOuter->GetSequenceCycleRate( pStudioHdr, iSequence ) * gpGlobals->frametime;
+ if ( flCurCycle > 1 )
+ {
+ if ( bWaitAtEnd )
+ {
+ flCurCycle = 1;
+ }
+ else
+ {
+ // Not firing anymore.
+ bEnabled = false;
+ iSequence = 0;
+ return;
+ }
+ }
+
+ CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( iLayer );
+
+ pLayer->m_flCycle = flCurCycle;
+ pLayer->m_nSequence = iSequence;
+
+ pLayer->m_flPlaybackRate = 1.0;
+ pLayer->m_flWeight = flWeight;
+ pLayer->m_nOrder = iLayer;
+
+}
+
+extern ConVar mp_facefronttime;
+extern ConVar mp_feetyawrate;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDODPlayerAnimState::Update( float eyeYaw, float eyePitch )
+{
+ // Profile the animation update.
+ VPROF( "CDODPlayerAnimState::Update" );
+
+ // Get the studio header for the player.
+ CStudioHdr *pStudioHdr = GetOuterDOD()->GetModelPtr();
+ if ( !pStudioHdr )
+ return;
+
+ // Check to see if we should be updating the animation state - dead, ragdolled?
+ if ( !ShouldUpdateAnimState() )
+ {
+ ClearAnimationState();
+ return;
+ }
+
+ // Store the eye angles.
+ m_flEyeYaw = AngleNormalize( eyeYaw );
+ m_flEyePitch = AngleNormalize( eyePitch );
+
+ // Clear animation overlays because we're about to completely reconstruct them.
+ ClearAnimationLayers();
+
+ // Compute the player sequences.
+ ComputeSequences( pStudioHdr );
+
+ if ( SetupPoseParameters( pStudioHdr ) )
+ {
+ // Pose parameter - what direction are the player's legs running in.
+ ComputePoseParam_MoveYaw( pStudioHdr );
+
+ // Pose parameter - Torso aiming (up/down).
+ ComputePoseParam_AimPitch( pStudioHdr );
+
+ // Pose parameter - Torso aiming (rotation).
+ ComputePoseParam_AimYaw( pStudioHdr );
+
+ // Pose parameter - Body Height (torso elevation).
+ ComputePoseParam_BodyHeight( pStudioHdr );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CDODPlayerAnimState::SetupPoseParameters( CStudioHdr *pStudioHdr )
+{
+ // Check to see if this has already been done.
+ if ( m_bPoseParameterInit )
+ return true;
+
+ // Save off the pose parameter indices.
+ if ( !pStudioHdr )
+ return false;
+
+ // Look for the movement blenders.
+ m_iMoveX = GetOuterDOD()->LookupPoseParameter( pStudioHdr, "move_x" );
+ m_iMoveY = GetOuterDOD()->LookupPoseParameter( pStudioHdr, "move_y" );
+ if ( ( m_iMoveX < 0 ) || ( m_iMoveY < 0 ) )
+ return false;
+
+ // Look for the aim pitch blender.
+ m_iAimPitch = GetOuterDOD()->LookupPoseParameter( pStudioHdr, "body_pitch" );
+ if ( m_iAimPitch < 0 )
+ return false;
+
+ // Look for aim yaw blender.
+ m_iAimYaw = GetOuterDOD()->LookupPoseParameter( pStudioHdr, "body_yaw" );
+ if ( m_iAimYaw < 0 )
+ return false;
+
+ // Look for the body height blender.
+ m_iBodyHeight = GetOuterDOD()->LookupPoseParameter( pStudioHdr, "body_height" );
+ if ( m_iBodyHeight < 0 )
+ return false;
+
+ m_bPoseParameterInit = true;
+
+ return true;
+}
+
+#define DOD_MOVEMENT_ERROR_LIMIT 1.0
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDODPlayerAnimState::ComputePoseParam_MoveYaw( CStudioHdr *pStudioHdr )
+{
+ // Check to see if we are deployed or prone.
+ if( GetOuterDOD()->m_Shared.IsInMGDeploy() || GetOuterDOD()->m_Shared.IsProne() )
+ {
+ // Set the 9-way blend movement pose parameters.
+ Vector2D vecCurrentMoveYaw( 0.0f, 0.0f );
+ GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveX, vecCurrentMoveYaw.x );
+ GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveY, vecCurrentMoveYaw.y );
+
+ m_vecLastMoveYaw = vecCurrentMoveYaw;
+
+#if 0
+ // Rotate the entire body instantly.
+ m_flGoalFeetYaw = AngleNormalize( m_flEyeYaw );
+ m_flCurrentFeetYaw = m_flGoalFeetYaw;
+ m_flLastTurnTime = gpGlobals->curtime;
+
+ // Rotate entire body into position.
+ m_angRender[YAW] = m_flCurrentFeetYaw;
+ m_angRender[PITCH] = m_angRender[ROLL] = 0;
+
+ SetOuterBodyYaw( m_flCurrentFeetYaw );
+ g_flLastBodyYaw = m_flCurrentFeetYaw;
+#endif
+ }
+ else
+ {
+ // Get the estimated movement yaw.
+ EstimateYaw();
+
+ // Get the view yaw.
+ float flAngle = AngleNormalize( m_flEyeYaw );
+
+ // rotate movement into local reference frame
+ float flYaw = flAngle - m_flEstimateYaw;
+ flYaw = AngleNormalize( -flYaw );
+
+ // Get the current speed the character is running.
+ Vector vecEstVelocity;
+ vecEstVelocity.x = cos( DEG2RAD( flYaw ) ) * m_flEstimateVelocity;
+ vecEstVelocity.y = sin( DEG2RAD( flYaw ) ) * m_flEstimateVelocity;
+
+ Vector2D vecCurrentMoveYaw( 0.0f, 0.0f );
+ // set the pose parameters to the correct direction, but not value
+ if ( vecEstVelocity.x != 0.0f && fabs( vecEstVelocity.x ) > fabs( vecEstVelocity.y ) )
+ {
+ vecCurrentMoveYaw.x = (vecEstVelocity.x < 0.0) ? -1.0 : 1.0;
+ vecCurrentMoveYaw.y = vecEstVelocity.y / fabs( vecEstVelocity.x );
+ }
+ else if (vecEstVelocity.y != 0.0f)
+ {
+ vecCurrentMoveYaw.y = (vecEstVelocity.y < 0.0) ? -1.0 : 1.0;
+ vecCurrentMoveYaw.x = vecEstVelocity.x / fabs( vecEstVelocity.y );
+ }
+
+#ifndef CLIENT_DLL
+ GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveX, vecCurrentMoveYaw.x );
+ GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveY, vecCurrentMoveYaw.y );
+#else
+
+ // refine pose parameters to be more accurate
+ int i = 0;
+ float dx, dy;
+ Vector vecAnimVelocity;
+
+ /*
+ if ( m_pOuter->entindex() == 2 )
+ {
+ GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveX, vecCurrentMoveYaw.x );
+ GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveY, vecCurrentMoveYaw.y );
+ GetOuterDOD()->GetBlendedLinearVelocity( &vecAnimVelocity );
+ DevMsgRT("(%.2f) %.3f : (%.2f) %.3f\n", vecAnimVelocity.x, vecCurrentMoveYaw.x, vecAnimVelocity.y, vecCurrentMoveYaw.y );
+ }
+ */
+
+ bool retry = true;
+ do
+ {
+ // Set the 9-way blend movement pose parameters.
+ GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveX, vecCurrentMoveYaw.x );
+ GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveY, vecCurrentMoveYaw.y );
+
+ GetOuterDOD()->GetBlendedLinearVelocity( &vecAnimVelocity );
+
+ // adjust X pose parameter based on movement error
+ if (fabs( vecAnimVelocity.x ) > 0.001)
+ {
+ vecCurrentMoveYaw.x *= vecEstVelocity.x / vecAnimVelocity.x;
+ }
+ else
+ {
+ vecCurrentMoveYaw.x = 0;
+ GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveX, vecCurrentMoveYaw.x );
+ }
+ // adjust Y pose parameter based on movement error
+ if (fabs( vecAnimVelocity.y ) > 0.001)
+ {
+ vecCurrentMoveYaw.y *= vecEstVelocity.y / vecAnimVelocity.y;
+ }
+ else
+ {
+ vecCurrentMoveYaw.y = 0;
+ GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveY, vecCurrentMoveYaw.y );
+ }
+
+ dx = vecEstVelocity.x - vecAnimVelocity.x;
+ dy = vecEstVelocity.y - vecAnimVelocity.y;
+
+ retry = (vecCurrentMoveYaw.x < 1.0 && vecCurrentMoveYaw.x > -1.0) && (dx < -DOD_MOVEMENT_ERROR_LIMIT || dx > DOD_MOVEMENT_ERROR_LIMIT);
+ retry = retry || ((vecCurrentMoveYaw.y < 1.0 && vecCurrentMoveYaw.y > -1.0) && (dy < -DOD_MOVEMENT_ERROR_LIMIT || dy > DOD_MOVEMENT_ERROR_LIMIT));
+
+ } while (i++ < 5 && retry);
+
+ /*
+ if ( m_pOuter->entindex() == 2 )
+ {
+ DevMsgRT("%d(%.2f : %.2f) %.3f : (%.2f : %.2f) %.3f\n",
+ i,
+ vecEstVelocity.x, vecAnimVelocity.x, vecCurrentMoveYaw.x,
+ vecEstVelocity.y, vecAnimVelocity.y, vecCurrentMoveYaw.y );
+ }
+ */
+#endif
+
+ m_vecLastMoveYaw = vecCurrentMoveYaw;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDODPlayerAnimState::EstimateYaw( void )
+{
+ // Get the frame time.
+ float flDeltaTime = gpGlobals->frametime;
+ if ( flDeltaTime == 0.0f )
+ {
+ // FIXME: why does this short circuit?
+ m_flEstimateVelocity = 0.0;
+ m_flEstimateYaw = 0.0;
+ return;
+ }
+
+ // Get the player's velocity and angles.
+ Vector vecEstVelocity;
+ GetOuterAbsVelocity( vecEstVelocity );
+ QAngle angles = GetOuterDOD()->GetLocalAngles();
+
+ // If we are not moving, sync up the feet and eyes slowly.
+ if ( vecEstVelocity.x == 0.0f && vecEstVelocity.y == 0.0f )
+ {
+ float flYawDelta = angles[YAW] - m_flEstimateYaw;
+ flYawDelta = AngleNormalize( flYawDelta );
+
+ if ( flDeltaTime < 0.25f )
+ {
+ flYawDelta *= ( flDeltaTime * 4.0f );
+ }
+ else
+ {
+ flYawDelta *= flDeltaTime;
+ }
+
+ m_flEstimateVelocity = 0.0;
+ m_flEstimateYaw += flYawDelta;
+ AngleNormalize( m_flEstimateYaw );
+ }
+ else
+ {
+ m_flEstimateVelocity = vecEstVelocity.Length2D();
+ m_flEstimateYaw = ( atan2( vecEstVelocity.y, vecEstVelocity.x ) * 180.0f / M_PI );
+ m_flEstimateYaw = clamp( m_flEstimateYaw, -180.0f, 180.0f );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDODPlayerAnimState::ComputePoseParam_AimPitch( CStudioHdr *pStudioHdr )
+{
+ // Get the view pitch.
+ float flAimPitch = m_flEyePitch;
+
+ // Lock pitch at 0 if a reload gesture is playing
+#ifdef CLIENT_DLL
+ if ( IsPlayingGesture( GESTURE_RELOAD ) )
+ flAimPitch = 0;
+#else
+ Activity idealActivity = TranslateActivity( ACT_RELOAD );
+
+ if ( m_pOuter->IsPlayingGesture( idealActivity ) )
+ flAimPitch = 0;
+#endif
+
+ // Set the aim pitch pose parameter and save.
+ GetOuter()->SetPoseParameter( pStudioHdr, m_iAimPitch, -flAimPitch );
+ m_flLastAimPitch = flAimPitch;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDODPlayerAnimState::ComputePoseParam_AimYaw( CStudioHdr *pStudioHdr )
+{
+ // Get the movement velocity.
+ Vector vecVelocity;
+ GetOuterAbsVelocity( vecVelocity );
+
+ // Check to see if we are moving.
+ bool bMoving = ( vecVelocity.Length() > 1.0f ) ? true : false;
+
+ // Check our prone and deployed state.
+ bool bDeployed = GetOuterDOD()->m_Shared.IsSandbagDeployed() || GetOuterDOD()->m_Shared.IsProneDeployed();
+ bool bProne = GetOuterDOD()->m_Shared.IsProne();
+
+ // If we are moving or are prone and undeployed.
+ if ( bMoving || ( bProne && !bDeployed ) )
+ {
+ // The feet match the eye direction when moving - the move yaw takes care of the rest.
+ m_flGoalFeetYaw = m_flEyeYaw;
+ }
+ // Else if we are not moving.
+ else
+ {
+ // Initialize the feet.
+ if ( m_flLastAimTurnTime <= 0.0f )
+ {
+ m_flGoalFeetYaw = m_flEyeYaw;
+ m_flCurrentFeetYaw = m_flEyeYaw;
+ m_flLastAimTurnTime = gpGlobals->curtime;
+ }
+ // Make sure the feet yaw isn't too far out of sync with the eye yaw.
+ // TODO: Do something better here!
+ else
+ {
+ float flYawDelta = AngleNormalize( m_flGoalFeetYaw - m_flEyeYaw );
+
+ if ( bDeployed )
+ {
+ if ( fabs( flYawDelta ) > 20.0f )
+ {
+ float flSide = ( flYawDelta > 0.0f ) ? -1.0f : 1.0f;
+ m_flGoalFeetYaw += ( 20.0f * flSide );
+ }
+ }
+ else
+ {
+ if ( fabs( flYawDelta ) > m_AnimConfig.m_flMaxBodyYawDegrees )
+ {
+ float flSide = ( flYawDelta > 0.0f ) ? -1.0f : 1.0f;
+ m_flGoalFeetYaw += ( m_AnimConfig.m_flMaxBodyYawDegrees * flSide );
+ }
+ }
+ }
+ }
+
+ // Fix up the feet yaw.
+ m_flGoalFeetYaw = AngleNormalize( m_flGoalFeetYaw );
+ if ( m_flGoalFeetYaw != m_flCurrentFeetYaw )
+ {
+ ConvergeYawAngles( m_flGoalFeetYaw, DOD_BODYYAW_RATE, gpGlobals->frametime, m_flCurrentFeetYaw );
+ m_flLastAimTurnTime = gpGlobals->curtime;
+ }
+
+ // Rotate the body into position.
+ m_angRender[YAW] = m_flCurrentFeetYaw;
+
+ // Find the aim(torso) yaw base on the eye and feet yaws.
+ float flAimYaw = m_flEyeYaw - m_flCurrentFeetYaw;
+ flAimYaw = AngleNormalize( flAimYaw );
+
+ // Set the aim yaw and save.
+ GetOuter()->SetPoseParameter( pStudioHdr, m_iAimYaw, -flAimYaw );
+ m_flLastAimYaw = flAimYaw;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDODPlayerAnimState::ConvergeYawAngles( float flGoalYaw, float flYawRate, float flDeltaTime, float &flCurrentYaw )
+{
+#define FADE_TURN_DEGREES 60.0f
+
+ // Find the yaw delta.
+ float flDeltaYaw = flGoalYaw - flCurrentYaw;
+ float flDeltaYawAbs = fabs( flDeltaYaw );
+ flDeltaYaw = AngleNormalize( flDeltaYaw );
+
+ // Always do at least a bit of the turn (1%).
+ float flScale = 1.0f;
+ flScale = flDeltaYawAbs / FADE_TURN_DEGREES;
+ flScale = clamp( flScale, 0.01f, 1.0f );
+
+ float flYaw = flYawRate * flDeltaTime * flScale;
+ if ( flDeltaYawAbs < flYaw )
+ {
+ flCurrentYaw = flGoalYaw;
+ }
+ else
+ {
+ float flSide = ( flDeltaYaw < 0.0f ) ? -1.0f : 1.0f;
+ flCurrentYaw += ( flYaw * flSide );
+ }
+
+ flCurrentYaw = AngleNormalize( flCurrentYaw );
+
+#undef FADE_TURN_DEGREES
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDODPlayerAnimState::ComputePoseParam_BodyHeight( CStudioHdr *pStudioHdr )
+{
+ if( m_pOuterDOD->m_Shared.IsSandbagDeployed() )
+ {
+// float flHeight = m_pOuterDOD->m_Shared.GetDeployedHeight() - 4.0f;
+ float flHeight = m_pOuterDOD->m_Shared.GetDeployedHeight() - dod_bodyheightoffset.GetFloat();
+ GetOuter()->SetPoseParameter( pStudioHdr, m_iBodyHeight, flHeight );
+ m_flLastBodyHeight = flHeight;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void Anim_StateLog( const char *pMsg, ... )
+{
+ // Format the string.
+ char str[4096];
+ va_list marker;
+ va_start( marker, pMsg );
+ Q_vsnprintf( str, sizeof( str ), pMsg, marker );
+ va_end( marker );
+
+ // Log it?
+ if ( anim_showstatelog.GetInt() == 1 || anim_showstatelog.GetInt() == 3 )
+ {
+ Msg( "%s", str );
+ }
+
+ if ( anim_showstatelog.GetInt() > 1 )
+ {
+// static FileHandle_t hFile = filesystem->Open( "AnimState.log", "wt" );
+// filesystem->FPrintf( hFile, "%s", str );
+// filesystem->Flush( hFile );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void Anim_StatePrintf( int iLine, const char *pMsg, ... )
+{
+ // Format the string.
+ char str[4096];
+ va_list marker;
+ va_start( marker, pMsg );
+ Q_vsnprintf( str, sizeof( str ), pMsg, marker );
+ va_end( marker );
+
+ // Show it with Con_NPrintf.
+ engine->Con_NPrintf( iLine, "%s", str );
+
+ // Log it.
+ Anim_StateLog( "%s\n", str );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDODPlayerAnimState::DebugShowAnimStateForPlayer( bool bIsServer )
+{
+ // Get the player's velocity.
+ Vector vecVelocity;
+ GetOuterAbsVelocity( vecVelocity );
+
+ // Start animation state logging.
+ int iLine = 5;
+ if ( bIsServer )
+ {
+ iLine = 12;
+ }
+// Anim_StateLog( "-------------%s: frame %d -----------------\n", bIsServer ? "Server" : "Client", gpGlobals->framecount );
+ Anim_StatePrintf( iLine++, "-------------%s: frame %d -----------------\n", bIsServer ? "Server" : "Client", gpGlobals->framecount );
+
+ // Write out the main sequence and its data.
+ Anim_StatePrintf( iLine++, "Main: %s, Cycle: %.2f\n", GetSequenceName( GetOuter()->GetModelPtr(), GetOuter()->GetSequence() ), GetOuter()->GetCycle() );
+
+ // Write out the layers and their data.
+ for ( int iAnim = 0; iAnim < GetOuter()->GetNumAnimOverlays(); ++iAnim )
+ {
+ CAnimationLayer *pLayer = GetOuter()->GetAnimOverlay( iAnim );
+ if ( pLayer && ( pLayer->m_nOrder != CBaseAnimatingOverlay::MAX_OVERLAYS ) )
+ {
+ Anim_StatePrintf( iLine++, "Layer %s: Weight: %.2f, Cycle: %.2f", GetSequenceName( GetOuter()->GetModelPtr(), pLayer->m_nSequence ), (float)pLayer->m_flWeight, (float)pLayer->m_flCycle );
+ }
+ }
+
+ // Write out the speed data.
+ Anim_StatePrintf( iLine++, "Time: %.2f, Speed: %.2f, MaxSpeed: %.2f", gpGlobals->curtime, vecVelocity.Length2D(), GetCurrentMaxGroundSpeed() );
+
+ // Write out the 9-way blend data.
+ Anim_StatePrintf( iLine++, "EntityYaw: %.2f, AimYaw: %.2f, AimPitch: %.2f, MoveX: %.2f, MoveY: %.2f Body: %.2f", m_angRender[YAW], m_flLastAimYaw, m_flLastAimPitch, m_vecLastMoveYaw.x, m_vecLastMoveYaw.y, m_flLastBodyHeight );
+
+// Anim_StateLog( "--------------------------------------------\n\n" );
+ Anim_StatePrintf( iLine++, "--------------------------------------------\n\n" );
+
+ DebugShowEyeYaw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDODPlayerAnimState::DebugShowEyeYaw( void )
+{
+#ifdef _NDEBUG
+
+ float flBaseSize = 10;
+ float flHeight = 80;
+
+ Vector vecPos = GetOuter()->GetAbsOrigin() + Vector( 0.0f, 0.0f, 3.0f );
+ QAngle angles( 0.0f, 0.0f, 0.0f );
+
+ angles[YAW] = m_flEyeYaw;
+
+ Vector vecForward, vecRight, vecUp;
+ AngleVectors( angles, &vecForward, &vecRight, &vecUp );
+
+ // Draw a red triangle on the ground for the eye yaw.
+ debugoverlay->AddTriangleOverlay( ( vecPos + vecRight * flBaseSize / 2.0f ),
+ ( vecPos - vecRight * flBaseSize / 2.0f ),
+ ( vecPos + vecForward * flHeight, 255, 0, 0, 255, false, 0.01f );
+
+#endif
+}
+
+// Client specific debug functions.
+#ifdef CLIENT_DLL
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDODPlayerAnimState::DebugShowActivity( Activity activity )
+{
+#ifdef _DEBUG
+
+ const char *pszActivity = "other";
+
+ switch( activity )
+ {
+ case ACT_IDLE:
+ {
+ pszActivity = "idle";
+ break;
+ }
+ case ACT_SPRINT:
+ {
+ pszActivity = "sprint";
+ break;
+ }
+ case ACT_WALK:
+ {
+ pszActivity = "walk";
+ break;
+ }
+ case ACT_RUN:
+ {
+ pszActivity = "run";
+ break;
+ }
+ }
+
+ Msg( "Activity: %s\n", pszActivity );
+
+#endif
+}
+
+#endif
diff --git a/game/shared/dod/dod_playeranimstate.h b/game/shared/dod/dod_playeranimstate.h
new file mode 100644
index 0000000..100b50d
--- /dev/null
+++ b/game/shared/dod/dod_playeranimstate.h
@@ -0,0 +1,62 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef DOD_PLAYERANIMSTATE_H
+#define DOD_PLAYERANIMSTATE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "convar.h"
+#include "iplayeranimstate.h"
+
+
+#if defined( CLIENT_DLL )
+ class C_DODPlayer;
+ #define CDODPlayer C_DODPlayer
+#else
+ class CDODPlayer;
+#endif
+
+enum PlayerAnimEvent_t
+{
+ PLAYERANIMEVENT_FIRE_GUN=0,
+ PLAYERANIMEVENT_THROW_GRENADE,
+ PLAYERANIMEVENT_ROLL_GRENADE,
+ PLAYERANIMEVENT_JUMP,
+ PLAYERANIMEVENT_RELOAD,
+ PLAYERANIMEVENT_SECONDARY_ATTACK,
+ PLAYERANIMEVENT_HANDSIGNAL,
+ PLAYERANIMEVENT_PLANT_TNT,
+ PLAYERANIMEVENT_DEFUSE_TNT,
+
+ PLAYERANIMEVENT_HS_NONE,
+ PLAYERANIMEVENT_CANCEL_GESTURES, // cancel current gesture
+
+ PLAYERANIMEVENT_COUNT
+};
+
+class IDODPlayerAnimState : virtual public IPlayerAnimState
+{
+public:
+ // This is called by both the client and the server in the same way to trigger events for
+ // players firing, jumping, throwing grenades, etc.
+ virtual void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 ) = 0;
+
+ virtual void ShowDebugInfo( void ) = 0;
+};
+
+
+IDODPlayerAnimState* CreatePlayerAnimState( CDODPlayer *pPlayer );
+
+
+// If this is set, then the game code needs to make sure to send player animation events
+// to the local player if he's the one being watched.
+extern ConVar cl_showanimstate;
+
+
+#endif // DOD_PLAYERANIMSTATE_H
diff --git a/game/shared/dod/dod_playerclass_info_parse.cpp b/game/shared/dod/dod_playerclass_info_parse.cpp
new file mode 100644
index 0000000..f76d2f1
--- /dev/null
+++ b/game/shared/dod/dod_playerclass_info_parse.cpp
@@ -0,0 +1,163 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "dod_playerclass_info_parse.h"
+#include "dod_shareddefs.h"
+#include "weapon_dodbase.h"
+#include <KeyValues.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+FilePlayerClassInfo_t* CreatePlayerClassInfo()
+{
+ return new CDODPlayerClassInfo;
+}
+
+CDODPlayerClassInfo::CDODPlayerClassInfo()
+{
+ m_iTeam= TEAM_UNASSIGNED;
+
+ m_iPrimaryWeapon= WEAPON_NONE;
+ m_iSecondaryWeapon= WEAPON_NONE;
+ m_iMeleeWeapon= WEAPON_NONE;
+
+ m_iNumGrensType1 = 0;
+ m_iGrenType1 = WEAPON_NONE;
+
+ m_iNumGrensType2 = 0;
+ m_iGrenType2 = WEAPON_NONE;
+
+ m_iNumBandages = 0;
+
+ m_iHelmetGroup= HELMET_GROUP_0;
+ m_iHairGroup= HELMET_GROUP_0;
+
+ m_iDropHelmet = HELMET_ALLIES;
+
+ m_szLimitCvar[0] = '\0';
+ m_bClassLimitMGMerge = false;
+}
+
+int AliasToWeaponID( const char *alias )
+{
+ if (alias)
+ {
+ for( int i=0; s_WeaponAliasInfo[i] != NULL; ++i )
+ if (!Q_stricmp( s_WeaponAliasInfo[i], alias ))
+ return i;
+ }
+
+ return WEAPON_NONE;
+}
+
+void CDODPlayerClassInfo::Parse( KeyValues *pKeyValuesData, const char *szWeaponName )
+{
+ BaseClass::Parse( pKeyValuesData, szWeaponName );
+
+ m_iTeam= pKeyValuesData->GetInt( "team", TEAM_UNASSIGNED );
+
+ // Figure out what team can have this player class
+ m_iTeam = TEAM_UNASSIGNED;
+ const char *pTeam = pKeyValuesData->GetString( "team", NULL );
+ if ( pTeam )
+ {
+ if ( Q_stricmp( pTeam, "ALLIES" ) == 0 )
+ {
+ m_iTeam = TEAM_ALLIES;
+ }
+ else if ( Q_stricmp( pTeam, "AXIS" ) == 0 )
+ {
+ m_iTeam = TEAM_AXIS;
+ }
+ else
+ {
+ Assert( false );
+ }
+ }
+ else
+ {
+ Assert( false );
+ }
+
+ const char *pszPrimaryWeapon = pKeyValuesData->GetString( "primaryweapon", NULL );
+ m_iPrimaryWeapon = AliasToWeaponID( pszPrimaryWeapon );
+ Assert( m_iPrimaryWeapon != WEAPON_NONE ); // require player to have a primary weapon
+
+ const char *pszSecondaryWeapon = pKeyValuesData->GetString( "secondaryweapon", NULL );
+
+ if ( pszSecondaryWeapon )
+ {
+ m_iSecondaryWeapon = AliasToWeaponID( pszSecondaryWeapon );
+ Assert( m_iSecondaryWeapon != WEAPON_NONE );
+ }
+ else
+ m_iSecondaryWeapon = WEAPON_NONE;
+
+ const char *pszMeleeWeapon = pKeyValuesData->GetString( "meleeweapon", NULL );
+ if ( pszMeleeWeapon )
+ {
+ m_iMeleeWeapon = AliasToWeaponID( pszMeleeWeapon );
+ Assert( m_iMeleeWeapon != WEAPON_NONE );
+ }
+ else
+ m_iMeleeWeapon = WEAPON_NONE;
+
+ m_iNumGrensType1 = pKeyValuesData->GetInt( "numgrens", 0 );
+ if ( m_iNumGrensType1 > 0 )
+ {
+ const char *pszGrenType1 = pKeyValuesData->GetString( "grenadetype", NULL );
+ m_iGrenType1 = AliasToWeaponID( pszGrenType1 );
+ Assert( m_iGrenType1 != WEAPON_NONE );
+ }
+
+ m_iNumGrensType2 = pKeyValuesData->GetInt( "numgrens2", 0 );
+ if ( m_iNumGrensType2 > 0 )
+ {
+ const char *pszGrenType2 = pKeyValuesData->GetString( "grenadetype2", NULL );
+ m_iGrenType2 = AliasToWeaponID( pszGrenType2 );
+ Assert( m_iGrenType2 != WEAPON_NONE );
+ }
+
+ m_iNumBandages = pKeyValuesData->GetInt( "numbandages", 0 );
+
+ m_iHelmetGroup = pKeyValuesData->GetInt( "helmetgroup", 0 );
+ m_iHairGroup = pKeyValuesData->GetInt( "hairgroup", 0 );
+
+ // Which helmet model to generate
+ const char *pszHelmetModel = pKeyValuesData->GetString( "drophelmet", "HELMET_ALLIES" );
+
+ if( pszHelmetModel )
+ {
+ if ( Q_stricmp( pszHelmetModel, "HELMET_ALLIES" ) == 0 )
+ {
+ m_iDropHelmet = HELMET_ALLIES;
+ }
+ else if ( Q_stricmp( pszHelmetModel, "HELMET_AXIS" ) == 0 )
+ {
+ m_iDropHelmet = HELMET_AXIS;
+ }
+ else
+ {
+ Assert( false );
+ }
+ }
+ else
+ {
+ Assert( false );
+ }
+
+ Q_strncpy( m_szLimitCvar, pKeyValuesData->GetString( "limitcvar", "!! Missing limit cvar on Player Class" ), sizeof(m_szLimitCvar) );
+
+ Assert( Q_strlen( m_szLimitCvar ) > 0 && "Every class must specify a limitcvar" );
+
+ m_bClassLimitMGMerge = ( pKeyValuesData->GetInt( "mergemgclass" ) > 0 );
+
+ // HUD player status health images (when the player is hurt)
+ Q_strncpy( m_szClassHealthImage, pKeyValuesData->GetString( "healthimage", "white" ), sizeof( m_szClassHealthImage ) );
+ Q_strncpy( m_szClassHealthImageBG, pKeyValuesData->GetString( "healthimagebg", "white" ), sizeof( m_szClassHealthImageBG ) );
+} \ No newline at end of file
diff --git a/game/shared/dod/dod_playerclass_info_parse.h b/game/shared/dod/dod_playerclass_info_parse.h
new file mode 100644
index 0000000..cb9d37a
--- /dev/null
+++ b/game/shared/dod/dod_playerclass_info_parse.h
@@ -0,0 +1,55 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef DOD_PLAYERCLASS_INFO_PARSE_H
+#define DOD_PLAYERCLASS_INFO_PARSE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "playerclass_info_parse.h"
+#include "networkvar.h"
+#include "dod_shareddefs.h"
+
+//--------------------------------------------------------------------------------------------------------
+class CDODPlayerClassInfo : public FilePlayerClassInfo_t
+{
+public:
+ DECLARE_CLASS_GAMEROOT( CDODPlayerClassInfo, FilePlayerClassInfo_t );
+
+ CDODPlayerClassInfo();
+
+ virtual void Parse( ::KeyValues *pKeyValuesData, const char *szWeaponName );
+
+ int m_iTeam; //which team. 2 == allies, 3 == axis
+
+ int m_iPrimaryWeapon;
+ int m_iSecondaryWeapon;
+ int m_iMeleeWeapon;
+
+ int m_iNumGrensType1;
+ int m_iGrenType1;
+
+ int m_iNumGrensType2;
+ int m_iGrenType2;
+
+ int m_iNumBandages;
+
+ int m_iHelmetGroup;
+ int m_iHairGroup; //what helmet group to switch to when the helmet comes off
+
+ int m_iDropHelmet;
+
+ char m_szLimitCvar[64]; //which cvar controls the class limit for this class
+ bool m_bClassLimitMGMerge; // merge class limits with this set to true
+
+ char m_szClassHealthImage[DOD_HUD_HEALTH_IMAGE_LENGTH];
+ char m_szClassHealthImageBG[DOD_HUD_HEALTH_IMAGE_LENGTH];
+};
+
+
+#endif // DOD_PLAYERCLASS_INFO_PARSE_H
diff --git a/game/shared/dod/dod_round_timer.cpp b/game/shared/dod/dod_round_timer.cpp
new file mode 100644
index 0000000..cf15855
--- /dev/null
+++ b/game/shared/dod/dod_round_timer.cpp
@@ -0,0 +1,183 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Dod gamerules round timer
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "dod_round_timer.h"
+
+#ifdef CLIENT_DLL
+
+ #include "iclientmode.h"
+ #include "vgui_controls/AnimationController.h"
+
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#ifdef CLIENT_DLL
+
+ // Use this proxy to flash the round timer whenever the timer is restarted
+ // because trapping the round start event doesn't work ( the event also flushes
+ // all hud events and obliterates our TimerFlash event )
+ static void RecvProxy_TimerPaused( const CRecvProxyData *pData, void *pStruct, void *pOut )
+ {
+ CDODRoundTimer *pTimer = (CDODRoundTimer *) pStruct;
+
+ bool bTimerPaused = ( pData->m_Value.m_Int > 0 );
+
+ if ( bTimerPaused == false )
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "TimerFlash" );
+ }
+
+ pTimer->InternalSetPaused( bTimerPaused );
+ }
+
+#endif
+
+LINK_ENTITY_TO_CLASS( dod_round_timer, CDODRoundTimer );
+
+IMPLEMENT_NETWORKCLASS_ALIASED( DODRoundTimer, DT_DODRoundTimer )
+
+BEGIN_NETWORK_TABLE_NOBASE( CDODRoundTimer, DT_DODRoundTimer )
+ #ifdef CLIENT_DLL
+
+ RecvPropInt( RECVINFO( m_bTimerPaused ), 0, RecvProxy_TimerPaused ),
+ RecvPropTime( RECVINFO( m_flTimeRemaining ) ),
+ RecvPropTime( RECVINFO( m_flTimerEndTime ) ),
+
+ #else
+
+ SendPropBool( SENDINFO( m_bTimerPaused ) ),
+ SendPropTime( SENDINFO( m_flTimeRemaining ) ),
+ SendPropTime( SENDINFO( m_flTimerEndTime ) ),
+
+ #endif
+END_NETWORK_TABLE()
+
+#ifdef CLIENT_DLL
+ CDODRoundTimer *g_DODRoundTimer = NULL;
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: constructor
+//-----------------------------------------------------------------------------
+CDODRoundTimer::CDODRoundTimer( void )
+{
+#ifndef CLIENT_DLL
+ m_bTimerPaused = true;
+ m_flTimeRemaining = 0;
+ m_iTimerMaxLength = 0;
+#else
+ g_DODRoundTimer = this;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: destructor
+//-----------------------------------------------------------------------------
+CDODRoundTimer::~CDODRoundTimer( void )
+{
+#ifdef CLIENT_DLL
+ g_DODRoundTimer = NULL;
+#endif
+}
+
+#ifndef CLIENT_DLL
+
+//-----------------------------------------------------------------------------
+// Purpose: The timer is always transmitted to clients
+//-----------------------------------------------------------------------------
+int CDODRoundTimer::UpdateTransmitState()
+{
+ // ALWAYS transmit to all clients.
+ return SetTransmitState( FL_EDICT_ALWAYS );
+}
+
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: To set the initial timer duration
+//-----------------------------------------------------------------------------
+void CDODRoundTimer::SetTimeRemaining( int iTimerSeconds )
+{
+ m_flTimeRemaining = (float)iTimerSeconds;
+ m_flTimerEndTime = gpGlobals->curtime + m_flTimeRemaining;
+ m_iTimerMaxLength = iTimerSeconds;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Timer is paused at round end, stops the countdown
+//-----------------------------------------------------------------------------
+void CDODRoundTimer::PauseTimer( void )
+{
+ if ( m_bTimerPaused == false )
+ {
+ m_bTimerPaused = true;
+
+ m_flTimeRemaining = m_flTimerEndTime - gpGlobals->curtime;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: To start or re-start the timer after a pause
+//-----------------------------------------------------------------------------
+void CDODRoundTimer::ResumeTimer( void )
+{
+ if ( m_bTimerPaused == true )
+ {
+ m_bTimerPaused = false;
+
+ m_flTimerEndTime = gpGlobals->curtime + m_flTimeRemaining;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets the seconds left on the timer, paused or not.
+//-----------------------------------------------------------------------------
+float CDODRoundTimer::GetTimeRemaining( void )
+{
+ float flSecondsRemaining;
+
+ if ( m_bTimerPaused )
+ {
+ flSecondsRemaining = m_flTimeRemaining;
+ }
+ else
+ {
+ flSecondsRemaining = m_flTimerEndTime - gpGlobals->curtime;
+ }
+
+ if ( flSecondsRemaining < 0 )
+ flSecondsRemaining = 0;
+
+ return flSecondsRemaining;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add seconds to the timer while it is running or paused
+//-----------------------------------------------------------------------------
+void CDODRoundTimer::AddTimerSeconds( int iSecondsToAdd )
+{
+ // do a hud animation indicating that time has been added
+
+ if ( m_bTimerPaused )
+ {
+ m_flTimeRemaining += (float)iSecondsToAdd;
+ }
+ else
+ {
+ m_flTimerEndTime += (float)iSecondsToAdd;
+ }
+
+ m_iTimerMaxLength += iSecondsToAdd;
+}
+
+int CDODRoundTimer::GetTimerMaxLength( void )
+{
+ return m_iTimerMaxLength;
+}
diff --git a/game/shared/dod/dod_round_timer.h b/game/shared/dod/dod_round_timer.h
new file mode 100644
index 0000000..8d65b41
--- /dev/null
+++ b/game/shared/dod/dod_round_timer.h
@@ -0,0 +1,67 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Round timer for dod gamerules
+//
+//=============================================================================//
+
+#ifndef DOD_ROUND_TIMER_H
+#define DOD_ROUND_TIMER_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#ifdef CLIENT_DLL
+ #define CDODRoundTimer C_DODRoundTimer
+#endif
+
+class CDODRoundTimer : public CBaseEntity
+{
+public:
+ DECLARE_CLASS( CDODRoundTimer, CBaseEntity );
+ DECLARE_NETWORKCLASS();
+
+ // Constructor
+ CDODRoundTimer();
+
+ // Destructor
+ virtual ~CDODRoundTimer();
+
+ // Set the initial length of the timer
+ void SetTimeRemaining( int iTimerSeconds );
+
+ // Add time to an already running ( or paused ) timer
+ void AddTimerSeconds( int iSecondsToAdd );
+
+ void PauseTimer( void );
+ void ResumeTimer( void );
+
+ // Returns seconds to display.
+ // When paused shows amount of time left once the timer is resumed
+ float GetTimeRemaining( void );
+
+ int GetTimerMaxLength( void );
+
+#ifndef CLIENT_DLL
+
+ int UpdateTransmitState();
+
+#else
+
+ void InternalSetPaused( bool bPaused ) { m_bTimerPaused = bPaused; }
+
+#endif
+
+private:
+ CNetworkVar( bool, m_bTimerPaused );
+ CNetworkVar( float, m_flTimeRemaining );
+ CNetworkVar( float, m_flTimerEndTime );
+
+ int m_iTimerMaxLength; // Sum of starting duration plus any time we added
+};
+
+#ifdef CLIENT_DLL
+ extern CDODRoundTimer *g_DODRoundTimer;
+#endif
+
+#endif //DOD_ROUND_TIMER_H \ No newline at end of file
diff --git a/game/shared/dod/dod_shareddefs.cpp b/game/shared/dod/dod_shareddefs.cpp
new file mode 100644
index 0000000..483fbfa
--- /dev/null
+++ b/game/shared/dod/dod_shareddefs.cpp
@@ -0,0 +1,276 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+#include "cbase.h"
+#include "dod_shareddefs.h"
+#include "weapon_dodbase.h"
+
+//Voice commands
+DodVoiceCommand_t g_VoiceCommands[] =
+{
+ //Voice command // Command Name //HS //Allied subtitle //german subtitle //brit subtitle
+
+ // Menu A
+ {"voice_attack", "Moveout", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_attack", "#Voice_subtitle_moveout"},
+ {"voice_hold", "Hold", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_hold" },
+ {"voice_left", "FlankLeft", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_left" },
+ {"voice_right", "FlankRight", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_right" },
+ {"voice_sticktogether", "StickTogether", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_sticktogether" },
+ {"voice_cover", "CoveringFire", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_cover" },
+ {"voice_usesmoke", "UseSmoke", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_usesmoke" },
+ {"voice_usegrens", "UseGrenades", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_usegrens" },
+ {"voice_ceasefire", "CeaseFire", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_ceasefire" },
+
+ // Menu B
+ {"voice_yessir", "YesSir", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_yessir" },
+ {"voice_negative", "Negative", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_negative" },
+ {"voice_backup", "BackUp", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_backup" },
+ {"voice_fireinhole", "FireInHole", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_fireinhole" },
+ {"voice_grenade", "Grenade", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_grenade" },
+ {"voice_sniper", "Sniper", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_sniper" },
+ {"voice_niceshot", "NiceShot", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_niceshot" },
+ {"voice_thanks", "Thanks", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_thanks" },
+ {"voice_areaclear", "Clear", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_areaclear" },
+
+ // Menu C
+ {"voice_dropweapons", "DropWeapons", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_dropyourweapons" },
+ {"voice_displace", "Displace", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_displace" },
+ {"voice_mgahead", "MgAhead", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_mgahead" },
+ {"voice_enemybehind", "BehindUs", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_enemybehind" },
+ {"voice_wegothim", "WeGotHim", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_wegothim" },
+ {"voice_moveupmg", "MoveUpMg", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_moveupmg_30cal", "#Voice_subtitle_moveupmg_mg", "#Voice_subtitle_moveupmg_bren"},
+ {"voice_needammo", "NeedAmmo", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_needammo" },
+ {"voice_usebazooka", "UseRocket", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_usebazooka", "#Voice_subtitle_usepschreck", "#Voice_subtitle_usepiat"},
+ {"voice_bazookaspotted","RocketSpotted", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_pschreckspotted", "#Voice_subtitle_bazookaspotted", "#Voice_subtitle_pschreckspotted"},
+
+ // Voice commands that aren't in a menu
+ {"voice_gogogo", "Moveout", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_attack", "#Voice_subtitle_moveout"},
+ {"voice_medic", "Medic", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_medic" },
+ {"voice_coverflanks", "CoverFlanks", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_coverflanks" },
+ {"voice_tank", "TankAhead", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_tigerahead", "#Voice_subtitle_tankahead*" },
+ {"voice_takeammo", "TakeAmmo", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_takeammo" },
+ {"voice_movewithtank", "MoveWithTank", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_movewithtank" },
+ {"voice_wtf", "WhiskeyTangoFoxtrot", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_wtf" },
+ {"voice_fireleft", "TakingFireLeft", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_fireleft" },
+ {"voice_fireright", "TakingFireRight", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_fireright" },
+ {"voice_mgahead", "MgAhead", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_mgahead" },
+ {"voice_enemyahead", "EnemyAhead", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_enemyahead" },
+ {"voice_fallback", "FallBack", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_fallback" },
+
+ // Must be last in the list
+ { NULL }
+};
+
+// Hand Signals
+DodHandSignal_t g_HandSignals[] =
+{
+ //command // anim event //subtitle
+
+ {"signal_sticktogether", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_sticktogether" },
+ {"signal_fallback", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_fallback" },
+ {"signal_no", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_negative" },
+ {"signal_yes", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_yessir" },
+ {"signal_sniper", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_sniper" },
+ {"signal_backup", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_backup" },
+ {"signal_enemyleft", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_fireleft" },
+ {"signal_enemyright", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_fireright" },
+ {"signal_grenade", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_grenade" },
+ {"signal_flankleft", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_left" },
+ {"signal_flankright", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_right" },
+ {"signal_moveout", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_attack" },
+ {"signal_areaclear", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_areaclear" },
+ {"signal_coveringfire", PLAYERANIMEVENT_HANDSIGNAL, "#Voice_subtitle_cover" },
+
+ // Must be last in the list
+ { NULL }
+};
+
+const char * s_WeaponAliasInfo[] =
+{
+ "none", // WEAPON_NONE = 0,
+
+ //Melee
+ "amerknife", //WEAPON_AMERKNIFE,
+ "spade", //WEAPON_SPADE,
+
+ //Pistols
+ "colt", //WEAPON_COLT,
+ "p38", //WEAPON_P38,
+ "c96", //WEAPON_C96
+
+ //Rifles
+ "garand", //WEAPON_GARAND,
+ "m1carbine", //WEAPON_M1CARBINE,
+ "k98", //WEAPON_K98,
+
+ //Sniper Rifles
+ "spring", //WEAPON_SPRING,
+ "k98_scoped", //WEAPON_K98_SCOPED,
+
+ //SMG
+ "thompson", //WEAPON_THOMPSON,
+ "mp40", //WEAPON_MP40,
+ "mp44", //WEAPON_MP44,
+ "bar", //WEAPON_BAR,
+
+ //Machine guns
+ "30cal", //WEAPON_30CAL,
+ "mg42", //WEAPON_MG42,
+
+ //Rocket weapons
+ "bazooka", //WEAPON_BAZOOKA,
+ "pschreck", //WEAPON_PSCHRECK,
+
+ //Grenades
+ "frag_us", //WEAPON_FRAG_US,
+ "frag_ger", //WEAPON_FRAG_GER,
+
+ "frag_us_live", //WEAPON_FRAG_US_LIVE
+ "frag_ger_live", //WEAPON_FRAG_GER_LIVE
+
+ "smoke_us", //WEAPON_SMOKE_US
+ "smoke_ger", //WEAPON_SMOKE_GER
+
+ "riflegren_us", //WEAPON_RIFLEGREN_US
+ "riflegren_ger", //WEAPON_RIFLEGREN_GER
+
+ "riflegren_us_live", //WEAPON_RIFLEGREN_US_LIVE
+ "riflegren_ger_live", //WEAPON_RIFLEGREN_GER_LIVE
+
+ // not actually separate weapons, but defines used in stats recording
+ "thompson_punch", //WEAPON_THOMPSON_PUNCH
+ "mp40_punch", //WEAPON_MP40_PUNCH
+ "garand_zoomed", //WEAPON_GARAND_ZOOMED,
+
+ "k98_zoomed", //WEAPON_K98_ZOOMED
+ "spring_zoomed", //WEAPON_SPRING_ZOOMED
+ "k98s_zoomed", //WEAPON_K98_SCOPED_ZOOMED
+
+ "30cal_undeployed", //WEAPON_30CAL_UNDEPLOYED,
+ "mg42_undeployed", //WEAPON_MG42_UNDEPLOYED,
+
+ "bar_semiauto", //WEAPON_BAR_SEMIAUTO,
+ "mp44_semiauto", //WEAPON_MP44_SEMIAUTO,
+
+ NULL, // end of list marker
+};
+
+const char *m_pszHelmetModels[NUM_HELMETS] =
+{
+ "models/helmets/helmet_american.mdl",
+ "models/helmets/helmet_german.mdl",
+};
+
+const char *g_pszHintMessages[] =
+{
+ "#Hint_spotted_a_friend",
+ "#Hint_spotted_an_enemy",
+ "#Hint_try_not_to_injure_teammates",
+ "#Hint_careful_around_teammates",
+ "#Hint_killing_enemies_is_good",
+ "#Hint_touched_area_capture",
+ "#Hint_touched_control_point",
+ "#Hint_picked_up_object",
+ "#Hint_mgs_fire_better_deployed",
+ "#Hint_sandbag_area_touch",
+ "#Hint_rocket_weapon_pickup",
+ "#Hint_out_of_ammo",
+ "#Hint_prone",
+ "#Hint_low_stamina",
+ "#Hint_area_requires_object",
+ "#Hint_player_killed_wavetime",
+ "#Hint_mg_overheat",
+ "#game_shoulder_rpg",
+ "#Hint_pick_up_weapon",
+ "#Hint_pick_up_grenade",
+ "#Hint_death_cam",
+ "#Hint_class_menu",
+ "#Hint_use_2e_melee",
+ "#Hint_use_zoom",
+ "#Hint_use_iron_sights",
+ "#Hint_use_semi_auto",
+ "#Hint_use_sprint",
+ "#Hint_use_deploy",
+ "#Hint_use_prime",
+ "#Hint_mg_deploy_usage",
+ "#Dod_mg_reload",
+ "#Hint_garand_reload",
+ "#Hint_turn_off_hints",
+ "#Hint_need_bomb_to_plant",
+ "#Hint_bomb_planted",
+ "#Hint_defuse_bomb",
+ "#Hint_bomb_target",
+ "#Hint_bomb_pickup",
+ "#Hint_bomb_defuse_onground",
+ "#Hint_bomb_plant_map",
+ "#Hint_bomb_first_select",
+};
+
+const char *pszTeamAlliesClasses[] =
+{
+ "us_garand",
+ "us_tommy",
+ "us_bar",
+ "us_spring",
+ "us_30cal",
+ "us_bazooka",
+ NULL
+};
+
+const char *pszTeamAxisClasses[] =
+{
+ "axis_k98",
+ "axis_mp40",
+ "axis_mp44",
+ "axis_k98s",
+ "axis_mg42",
+ "axis_pschreck",
+ NULL
+};
+
+const char *pszWinPanelCategoryHeaders[] =
+{
+ "",
+ "#winpanel_topbomb",
+ "#winpanel_topcappers",
+ "#winpanel_topdefenders",
+ "#winpanel_kills"
+};
+
+const char *g_pszAchievementAwards[NUM_ACHIEVEMENT_AWARDS] =
+{
+ "",
+ "DOD_KILLS_AS_RIFLEMAN",
+ "DOD_KILLS_AS_ASSAULT",
+ "DOD_KILLS_AS_SUPPORT",
+ "DOD_KILLS_AS_SNIPER",
+ "DOD_KILLS_AS_MG",
+ "DOD_KILLS_AS_BAZOOKAGUY",
+ "DOD_ALL_PACK_1",
+};
+
+const char *g_pszAchievementAwardMaterials_Allies[NUM_ACHIEVEMENT_AWARDS] =
+{
+ "sprites/player_icons/american",
+ "sprites/player_icons/american_rifleman",
+ "sprites/player_icons/american_assault",
+ "sprites/player_icons/american_support",
+ "sprites/player_icons/american_sniper",
+ "sprites/player_icons/american_mg",
+ "sprites/player_icons/american_rocket",
+ "sprites/player_icons/american_hero",
+};
+
+const char *g_pszAchievementAwardMaterials_Axis[NUM_ACHIEVEMENT_AWARDS] =
+{
+ "sprites/player_icons/german",
+ "sprites/player_icons/german_rifleman",
+ "sprites/player_icons/german_assault",
+ "sprites/player_icons/german_support",
+ "sprites/player_icons/german_sniper",
+ "sprites/player_icons/german_mg",
+ "sprites/player_icons/german_rocket",
+ "sprites/player_icons/german_hero",
+}; \ No newline at end of file
diff --git a/game/shared/dod/dod_shareddefs.h b/game/shared/dod/dod_shareddefs.h
new file mode 100644
index 0000000..35bae96
--- /dev/null
+++ b/game/shared/dod/dod_shareddefs.h
@@ -0,0 +1,691 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef DOD_SHAREDDEFS_H
+#define DOD_SHAREDDEFS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "dod_playeranimstate.h"
+
+
+#define DOD_PLAYER_VIEW_OFFSET Vector( 0, 0, 54 )
+
+// DOD Team IDs.
+#define TEAM_ALLIES 2
+#define TEAM_AXIS 3
+#define TEAM_MAXCOUNT 4 // update this if we ever add teams (unlikely)
+
+enum SubTeam
+{
+ SUBTEAM_NORMAL = 0,
+ SUBTEAM_PARA,
+ SUBTEAM_ALT_NATION,
+ NUM_SUBTEAMS
+};
+
+#define MAX_CONTROL_POINTS 8
+#define MAX_CONTROL_POINT_GROUPS 8
+
+#define DEATH_CAM_TIME 5.0f
+
+#define MAX_WAVE_RESPAWN_TIME 20.0f
+
+#define DOD_BOMB_TIMER_LENGTH 20
+#define DOD_BOMB_DEFUSE_TIME 3.0f
+#define DOD_BOMB_PLANT_TIME 2.0f
+#define DOD_BOMB_PLANT_RADIUS 80
+#define DOD_BOMB_DEFUSE_MAXDIST 96.0f
+
+enum
+{
+ CAP_EVENT_NONE,
+ CAP_EVENT_BOMB,
+ CAP_EVENT_FLAG,
+ CAP_EVENT_TIMER_EXPIRE
+};
+
+enum
+{
+ WINPANEL_TOP3_NONE,
+ WINPANEL_TOP3_BOMBERS,
+ WINPANEL_TOP3_CAPPERS,
+ WINPANEL_TOP3_DEFENDERS,
+ WINPANEL_TOP3_KILLERS
+};
+
+//--------------
+// DoD Specific damage flags
+//--------------
+
+// careful when reusing HL2 DMG_ flags, some of them cancel out the damage, eg if they are in DMG_TIMEBASED
+
+#define DMG_STUN (DMG_PARALYZE) //(1<<15)
+#define DMG_MACHINEGUN (DMG_LASTGENERICFLAG<<1) //(1<<30)
+#define DMG_BOMB (DMG_LASTGENERICFLAG<<2) //(1<<31)
+
+//END OF THE EXTENDABLE LIST!! Start reusing HL2 specific flags
+
+#define MELEE_DMG_SECONDARYATTACK (1<<0)
+#define MELEE_DMG_FIST (1<<1)
+#define MELEE_DMG_EDGE (1<<2)
+#define MELEE_DMG_STRONGATTACK (1<<3)
+
+#define SANDBAG_NOT_TOUCHING 0
+#define SANDBAG_TOUCHING 1
+#define SANDBAG_TOUCHING_ALIGNED 2
+#define SANDBAG_DEPLOYED 3
+
+#define PRONE_DEPLOY_HEIGHT -1
+
+#define STANDING_DEPLOY_HEIGHT 58
+#define CROUCHING_DEPLOY_HEIGHT 28
+#define TIME_TO_DEPLOY 0.3
+
+#define MIN_DEPLOY_PITCH 45
+#define MAX_DEPLOY_PITCH -60
+
+#define VEC_DUCK_MOVING_HULL_MIN Vector(-16, -16, 0 )
+#define VEC_DUCK_MOVING_HULL_MAX Vector( 16, 16, 55 )
+
+#define VEC_PRONE_HULL_MIN DODGameRules()->GetDODViewVectors()->m_vProneHullMin
+#define VEC_PRONE_HULL_MAX DODGameRules()->GetDODViewVectors()->m_vProneHullMax // MUST be shorter than duck hull for deploy check
+
+#define VEC_PRONE_HULL_MIN_SCALED( player ) ( DODGameRules()->GetDODViewVectors()->m_vProneHullMin * player->GetModelScale() )
+#define VEC_PRONE_HULL_MAX_SCALED( player ) ( DODGameRules()->GetDODViewVectors()->m_vProneHullMax * player->GetModelScale() )
+
+#define VEC_PRONE_HELPER_HULL_MIN Vector(-48, -48, 0 )
+#define VEC_PRONE_HELPER_HULL_MAX Vector( 48, 48, 24 )
+
+#define GRENADE_FUSE_LENGTH 5.0
+#define RIFLEGRENADE_FUSE_LENGTH 3.5
+
+#define CONTENTS_PRONE_HELPER 0x80000000
+
+#define PASS_OUT_CHANGE_TIME 1.5
+#define PASS_OUT_GET_UP_TIME 1.5
+
+// DOD-specific viewport panels
+#define PANEL_TEAM "team"
+#define PANEL_CLASS_ALLIES "class_us"
+#define PANEL_CLASS_AXIS "class_ger"
+#define PANEL_BACKGROUND "background"
+
+#define COLOR_DOD_GREEN Color(77, 121, 66, 255) // Color(76, 102, 76, 255)
+#define COLOR_DOD_RED Color(255, 64, 64, 255)
+
+#define DOD_HUD_HEALTH_IMAGE_LENGTH 64
+
+// The various states the player can be in during the join game process.
+enum DODPlayerState
+{
+ // Happily running around in the game.
+ // This state can jump to a bunch of other states like STATE_PICKINGCLASS or STATE_DEATH_ANIM.
+ STATE_ACTIVE=0,
+
+ // This is the state you're in when you first enter the server.
+ // It's switching between intro cameras every few seconds, and there's a level info
+ // screen up.
+ STATE_WELCOME, // Show the level intro screen.
+
+ // During these states, you can either be a new player waiting to join, or
+ // you can be a live player in the game who wants to change teams.
+ // Either way, you can't move while choosing team or class (or while any menu is up).
+ STATE_PICKINGTEAM, // Choosing team.
+ STATE_PICKINGCLASS, // Choosing class.
+
+ STATE_DEATH_ANIM, // Playing death anim, waiting for that to finish.
+ STATE_DEATH_OBSERVING, // Done playing death anim. Waiting for keypress to go into observer mode.
+ STATE_OBSERVER_MODE, // Noclipping around, watching players, etc.
+
+ NUM_PLAYER_STATES
+};
+
+enum DODRoundState
+{
+ // initialize the game, create teams
+ STATE_INIT=0,
+
+ //Before players have joined the game. Periodically checks to see if enough players are ready
+ //to start a game. Also reverts to this when there are no active players
+ STATE_PREGAME,
+
+ //The game is about to start, wait a bit and spawn everyone
+ STATE_STARTGAME,
+
+ //All players are respawned, frozen in place
+ STATE_PREROUND,
+
+ //Round is on, playing normally
+ STATE_RND_RUNNING,
+
+ //Someone has won the round
+ STATE_ALLIES_WIN,
+ STATE_AXIS_WIN,
+
+ //Noone has won, manually restart the game, reset scores
+ STATE_RESTART,
+
+ //Game is over, showing the scoreboard etc
+ STATE_GAME_OVER,
+
+ NUM_ROUND_STATES
+};
+
+#define PLAYERCLASS_RANDOM -2
+#define PLAYERCLASS_UNDEFINED -1
+
+#define DOD_PLAYERMODEL_AXIS_RIFLEMAN "models/player/german_rifleman.mdl"
+#define DOD_PLAYERMODEL_AXIS_ASSAULT "models/player/german_assault.mdl"
+#define DOD_PLAYERMODEL_AXIS_SUPPORT "models/player/german_support.mdl"
+#define DOD_PLAYERMODEL_AXIS_SNIPER "models/player/german_sniper.mdl"
+#define DOD_PLAYERMODEL_AXIS_MG "models/player/german_mg.mdl"
+#define DOD_PLAYERMODEL_AXIS_ROCKET "models/player/german_rocket.mdl"
+
+#define DOD_PLAYERMODEL_US_RIFLEMAN "models/player/american_rifleman.mdl"
+#define DOD_PLAYERMODEL_US_ASSAULT "models/player/american_assault.mdl"
+#define DOD_PLAYERMODEL_US_SUPPORT "models/player/american_support.mdl"
+#define DOD_PLAYERMODEL_US_SNIPER "models/player/american_sniper.mdl"
+#define DOD_PLAYERMODEL_US_MG "models/player/american_mg.mdl"
+#define DOD_PLAYERMODEL_US_ROCKET "models/player/american_rocket.mdl"
+
+typedef struct DodClassInfo_s
+{
+ char selectcmd[32];
+ char classname[128];
+ char modelname[128];
+
+ int team; //which team. 0 == allies, 1 == axis
+
+ int primarywpn;
+ int secondarywpn;
+ int meleewpn;
+
+ int numgrenades;
+ int armskin; //what skin does this class show in grenades / knives
+
+ int headgroup; //bodygroups
+ int helmetgroup;
+ int geargroup;
+ int bodygroup;
+ int hairgroup; //what helmet group to switch to when the helmet comes off
+
+} DodClassInfo_t;
+
+extern DodClassInfo_t g_ClassInfo[]; //a structure to hold all of the classes
+extern DodClassInfo_t g_ParaClassInfo[];
+
+// Voice Commands
+typedef struct DodVoiceCommand_s
+{
+ const char *pszCommandName; // console command that will produce the voice command
+
+ const char *pszSoundName; // name of sound to play
+
+ PlayerAnimEvent_t iHandSignal; //index into the hand signal array
+
+ const char *pszAlliedSubtitle; // subtitles for each nationality
+ const char *pszAxisSubtitle;
+ const char *pszBritishSubtitle;
+
+} DodVoiceCommand_t;
+
+extern DodVoiceCommand_t g_VoiceCommands[];
+
+// Hand Signals
+typedef struct DodHandSignal_s
+{
+ const char *pszCommandName; // console command that will produce the voice command
+
+ PlayerAnimEvent_t iHandSignal; //index into the hand signal array
+
+ const char *pszSubtitle; // subtitles for each nationality
+
+} DodHandSignal_t;
+
+extern DodHandSignal_t g_HandSignals[];
+
+#define ARM_SKIN_UNDEFINED 0
+
+enum
+{
+ HEAD_GROUP_0 = 0,
+ HEAD_GROUP_1,
+ HEAD_GROUP_2,
+ HEAD_GROUP_3,
+ HEAD_GROUP_4,
+ HEAD_GROUP_5,
+ HEAD_GROUP_6,
+};
+
+enum
+{
+ HELMET_GROUP_0 = 0,
+ HELMET_GROUP_1,
+ HELMET_GROUP_2,
+ HELMET_GROUP_3,
+ HELMET_GROUP_4,
+ HELMET_GROUP_5,
+ HELMET_GROUP_6,
+ HELMET_GROUP_7,
+};
+
+enum
+{
+ BODY_GROUP_0 = 0,
+ BODY_GROUP_1,
+ BODY_GROUP_2,
+ BODY_GROUP_3,
+ BODY_GROUP_4,
+ BODY_GROUP_5,
+};
+
+enum
+{
+ GEAR_GROUP_0 = 0,
+ GEAR_GROUP_1,
+ GEAR_GROUP_2,
+ GEAR_GROUP_3,
+ GEAR_GROUP_4,
+ GEAR_GROUP_5,
+ GEAR_GROUP_6,
+};
+
+enum
+{
+ BODYGROUP_BODY = 0,
+ BODYGROUP_HELMET,
+ BODYGROUP_HEAD,
+ BODYGROUP_GEAR,
+ BODYGROUP_JUMPGEAR
+};
+
+enum
+{
+ BODYGROUP_HEAD1 = 0,
+ BODYGROUP_HEAD2,
+ BODYGROUP_HEAD3,
+ BODYGROUP_HEAD4,
+ BODYGROUP_HEAD5,
+ BODYGROUP_HEAD6,
+ BODYGROUP_HEAD7
+};
+
+//helmet groups
+#define BODYGROUP_HELMET_ON 0
+
+#define BODYGROUP_ALLIES_HELMET_HELMET1 0
+#define BODYGROUP_ALLIES_HELMET_HELMET2 1
+#define BODYGROUP_ALLIES_HELMET_OFF 2
+
+#define BODYGROUP_AXIS_HAIR0 1
+#define BODYGROUP_AXIS_HAIR1 2
+#define BODYGROUP_AXIS_HAIR2 3
+#define BODYGROUP_AXIS_HAIR3 4
+#define BODYGROUP_AXIS_HAIR4 5
+#define BODYGROUP_AXIS_HAIR5 6
+#define BODYGROUP_AXIS_HAIR6 7
+
+//battle gear groups
+#define BODYGROUP_TOMMYGEAR 0
+#define BODYGROUP_SPRINGGEAR 1
+#define BODYGROUP_GARANDGEAR 2
+#define BODYGROUP_MGGEAR 3
+#define BODYGROUP_BARGEAR 4
+#define BODYGROUP_CARBGEAR 5
+#define BODYGROUP_GREASEGUNGEAR 6
+
+//jump gear
+#define BODYGROUP_JUMPGEAR_OFF 0
+#define BODYGROUP_JUMPGEAR_ON 1
+
+enum
+{
+ HELMET_ALLIES = 0,
+ HELMET_AXIS,
+
+ NUM_HELMETS
+};
+
+extern const char *m_pszHelmetModels[NUM_HELMETS];
+
+//Materials
+/*
+#define CHAR_TEX_CONCRETE 'C' // texture types
+#define CHAR_TEX_METAL 'M'
+#define CHAR_TEX_DIRT 'D'
+#define CHAR_TEX_GRATE 'G'
+#define CHAR_TEX_TILE 'T'
+#define CHAR_TEX_WOOD 'W'
+#define CHAR_TEX_GLASS 'Y'
+#define CHAR_TEX_FLESH 'F'
+#define CHAR_TEX_WATER 'S'
+#define CHAR_TEX_ROCK 'R'
+#define CHAR_TEX_SAND 'A'
+#define CHAR_TEX_GRAVEL 'L'
+#define CHAR_TEX_STUCCO 'Z'
+#define CHAR_TEX_BRICK 'B'
+#define CHAR_TEX_SNOW 'N'
+#define CHAR_TEX_HEAVYMETAL 'H'
+#define CHAR_TEX_LEAVES 'E'
+#define CHAR_TEX_SKY 'K'
+#define CHAR_TEX_GRASS 'P'
+*/
+
+
+#define WPN_SLOT_PRIMARY 0
+#define WPN_SLOT_SECONDARY 1
+#define WPN_SLOT_MELEE 2
+#define WPN_SLOT_GRENADES 3
+#define WPN_SLOT_BOMB 4
+
+#define SLEEVE_AXIS 0
+#define SLEEVE_ALLIES 1
+
+#define VM_BODYGROUP_GUN 0
+#define VM_BODYGROUP_SLEEVE 1
+
+#define PLAYER_SPEED_FROZEN 1
+#define PLAYER_SPEED_PRONE 50
+#define PLAYER_SPEED_PRONE_ZOOMED 30
+#define PLAYER_SPEED_PRONE_BAZOOKA_DEPLOYED 30
+#define PLAYER_SPEED_ZOOMED 42
+#define PLAYER_SPEED_BAZOOKA_DEPLOYED 50
+#define PLAYER_SPEED_NORMAL 600.0f
+
+#define PLAYER_SPEED_SLOWED 120
+#define PLAYER_SPEED_RUN 220
+#define PLAYER_SPEED_SPRINT 330
+
+#define PUSHAWAY_THINK_INTERVAL (1.0f / 20.0f)
+
+#define VEC_PRONE_VIEW Vector(0,0,10)
+#define VEC_PRONE_VIEW_SCALED( player ) ( Vector(0,0,10) * player->GetModelScale() )
+
+#define TIME_TO_PRONE 1.2f // should be 1.5!
+
+#define INITIAL_SPRINT_STAMINA_PENALTY 15
+#define LOW_STAMINA_THRESHOLD 35
+
+// changed to 80% of goldsrc values, gives the same end result
+#define ZOOM_SWAY_PRONE 0.1
+#define ZOOM_SWAY_DUCKING 0.2
+#define ZOOM_SWAY_STANDING 0.5
+#define ZOOM_SWAY_MOVING_PENALTY 0.4
+
+extern const char * s_WeaponAliasInfo[];
+
+enum
+{
+ //Dod hint messages
+ HINT_FRIEND_SEEN = 0, // #Hint_spotted_a_friend
+ HINT_ENEMY_SEEN, // #Hint_spotted_an_enemy
+ HINT_FRIEND_INJURED, // #Hint_try_not_to_injure_teammates
+ HINT_FRIEND_KILLED, // #Hint_careful_around_teammates
+ HINT_ENEMY_KILLED, // #Hint_killing_enemies_is_good
+ HINT_IN_AREA_CAP, // #Hint_touched_area_capture
+ HINT_FLAG_TOUCH, // #Hint_touched_control_point
+ HINT_OBJECT_PICKUP, // #Hint_picked_up_object
+ HINT_MG_FIRE_UNDEPLOYED, // #Hint_mgs_fire_better_deployed
+ HINT_SANDBAG_AREA, // #Hint_sandbag_area_touch
+ HINT_BAZOOKA_PICKUP, // #Hint_rocket_weapon_pickup
+ HINT_AMMO_EXHAUSTED, // #Hint_out_of_ammo
+ HINT_PRONE, // #Hint_prone
+ HINT_LOW_STAMINA, // #Hint_low_stamina
+ HINT_OBJECT_REQUIRED, // #Hint_area_requires_object
+ HINT_PLAYER_KILLED_WAVETIME, // #Hint_player_killed_wavetime
+ HINT_WEAPON_OVERHEAT, // #Hint_mg_overheat
+ HINT_SHOULDER_WEAPON, // #game_shoulder_rpg
+
+ HINT_PICK_UP_WEAPON, // #Hint_pick_up_weapon
+ HINT_PICK_UP_GRENADE, // #Hint_pick_up_grenade
+ HINT_DEATHCAM, // #Hint_death_cam
+ HINT_CLASSMENU, // #Hint_class_menu
+
+ HINT_USE_MELEE, // #Hint_use_2e_melee
+ HINT_USE_ZOOM, // #Hint_use_zoom
+ HINT_USE_IRON_SIGHTS, // #Hint_use_iron_sights
+ HINT_USE_SEMI_AUTO, // #Hint_use_semi_auto
+ HINT_USE_SPRINT, // #Hint_use_sprint
+ HINT_USE_DEPLOY, // #Hint_use_deploy
+ HINT_USE_PRIME, // #Hint_use_prime
+
+ HINT_MG_DEPLOY_USAGE, // #Hint_mg_deploy_usage
+
+ HINT_MG_DEPLOY_TO_RELOAD, // #Dod_mg_reload
+ HINT_GARAND_RELOAD, // #Hint_garand_reload
+
+ HINT_TURN_OFF_HINTS, // #Hint_turn_off_hints
+
+ HINT_NEED_BOMB, // #Hint_need_bomb_to_plant
+ HINT_BOMB_PLANTED, // #Hint_bomb_planted
+ HINT_DEFUSE_BOMB, // #Hint_defuse_bomb
+ HINT_BOMB_TARGET, // #Hint_bomb_target
+ HINT_BOMB_PICKUP, // #Hint_bomb_pickup
+ HINT_BOMB_DEFUSE_ONGROUND, // #Hint_bomb_defuse_onground
+
+ HINT_BOMB_PLANT_MAP, // #Hint_bomb_plant_map
+ HINT_BOMB_FIRST_SELECT, // #Hint_bomb_first_select
+
+ NUM_HINTS
+};
+
+extern const char *g_pszHintMessages[];
+
+// HINT_xxx bits to clear when the round restarts
+#define HINT_MASK_SPAWN_CLEAR ( 1 << HINT_FRIEND_KILLED )
+
+// criteria for when a weapon model wants to use an alt model
+#define ALTWPN_CRITERIA_NONE 0
+#define ALTWPN_CRITERIA_FIRING (1 << 0)
+#define ALTWPN_CRITERIA_RELOADING (1 << 1)
+#define ALTWPN_CRITERIA_DEPLOYED (1 << 2)
+#define ALTWPN_CRITERIA_DEPLOYED_RELOAD (1 << 3)
+#define ALTWPN_CRITERIA_PRONE (1 << 4) // player is prone
+#define ALTWPN_CRITERIA_PRONE_DEPLOYED_RELOAD (1 << 5) // player should use special alt model when prone deployed reloading
+
+// eject brass shells
+#define EJECTBRASS_PISTOL 0
+#define EJECTBRASS_RIFLE 1
+#define EJECTBRASS_MG 2
+#define EJECTBRASS_MG_2 3 // ?
+#define EJECTBRASS_GARANDCLIP 4
+
+extern const char *pszTeamAlliesClasses[];
+extern const char *pszTeamAxisClasses[];
+
+enum
+{
+ DOD_COLLISIONGROUP_SHELLS = LAST_SHARED_COLLISION_GROUP,
+ DOD_COLLISIONGROUP_BLOCKERWALL,
+};
+
+enum
+{
+ PROGRESS_BAR_BANDAGER = 0,
+ PROGRESS_BAR_BANDAGEE,
+ PROGRESS_BAR_CAP, // done by objective resource
+
+ NUM_PROGRESS_BAR_TYPES
+};
+
+// used for the corner cut panels in the HUD
+enum
+{
+ DOD_CORNERCUT_PANEL_BOTTOMRIGHT = 0,
+ DOD_CORNERCUT_PANEL_BOTTOMLEFT,
+ DOD_CORNERCUT_PANEL_TOPRIGHT,
+ DOD_CORNERCUT_PANEL_TOPLEFT,
+};
+
+enum ViewAnimationType {
+ VIEW_ANIM_LINEAR_Z_ONLY,
+ VIEW_ANIM_SPLINE_Z_ONLY,
+ VIEW_ANIM_EXPONENTIAL_Z_ONLY,
+};
+
+enum BombTargetState
+{
+ // invisible, not active
+ BOMB_TARGET_INACTIVE=0,
+
+ // visible, accepts planting +use
+ BOMB_TARGET_ACTIVE,
+
+ // visible, accepts disarm +use, counts down to explosion
+ // if disarmed, returns to BOMB_TARGET_ACTIVE
+ // if explodes, returns to BOMB_TARGET_INACTIVE
+ BOMB_TARGET_ARMED,
+
+ NUM_BOMB_TARGET_STATES
+};
+
+extern const char *pszWinPanelCategoryHeaders[];
+
+enum
+{
+ // Season 1
+ ACHIEVEMENT_DOD_THROW_BACK_GREN = 0,
+ ACHIEVEMENT_DOD_CONSECUTIVE_HEADSHOTS,
+ ACHIEVEMENT_DOD_MG_POSITION_STREAK,
+ ACHIEVEMENT_DOD_WIN_KNIFE_FIGHT,
+ ACHIEVEMENT_DOD_PLAY_CUSTOM_MAPS,
+ ACHIEVEMENT_DOD_KILLS_WITH_GRENADE,
+ ACHIEVEMENT_DOD_LONG_RANGE_ROCKET,
+ ACHIEVEMENT_DOD_END_ROUND_KILLS,
+ ACHIEVEMENT_DOD_CAP_LAST_FLAG,
+ ACHIEVEMENT_DOD_USE_ENEMY_WEAPONS,
+ ACHIEVEMENT_DOD_KILL_DOMINATING_MG,
+ ACHIEVEMENT_DOD_COLMAR_DEFENSE,
+ ACHIEVEMENT_DOD_BLOCK_CAPTURES,
+ ACHIEVEMENT_DOD_JAGD_OVERTIME_CAP,
+ ACHIEVEMENT_DOD_WEAPON_MASTERY,
+
+ // grinds
+ ACHIEVEMENT_DOD_KILLS_AS_ALLIES,
+ ACHIEVEMENT_DOD_KILLS_AS_AXIS,
+
+ ACHIEVEMENT_DOD_KILLS_AS_RIFLEMAN,
+ ACHIEVEMENT_DOD_KILLS_AS_ASSAULT,
+ ACHIEVEMENT_DOD_KILLS_AS_SUPPORT,
+ ACHIEVEMENT_DOD_KILLS_AS_SNIPER,
+ ACHIEVEMENT_DOD_KILLS_AS_MG,
+ ACHIEVEMENT_DOD_KILLS_AS_BAZOOKAGUY,
+
+ ACHIEVEMENT_DOD_KILLS_WITH_GARAND,
+ ACHIEVEMENT_DOD_KILLS_WITH_THOMPSON,
+ ACHIEVEMENT_DOD_KILLS_WITH_BAR,
+ ACHIEVEMENT_DOD_KILLS_WITH_SPRING,
+ ACHIEVEMENT_DOD_KILLS_WITH_30CAL,
+ ACHIEVEMENT_DOD_KILLS_WITH_BAZOOKA,
+ ACHIEVEMENT_DOD_KILLS_WITH_K98,
+ ACHIEVEMENT_DOD_KILLS_WITH_MP40,
+ ACHIEVEMENT_DOD_KILLS_WITH_MP44,
+ ACHIEVEMENT_DOD_KILLS_WITH_K98SCOPED,
+ ACHIEVEMENT_DOD_KILLS_WITH_MG42,
+ ACHIEVEMENT_DOD_KILLS_WITH_PSCHRECK,
+ ACHIEVEMENT_DOD_KILLS_WITH_COLT,
+ ACHIEVEMENT_DOD_KILLS_WITH_P38,
+ ACHIEVEMENT_DOD_KILLS_WITH_C96,
+ ACHIEVEMENT_DOD_KILLS_WITH_M1CARBINE,
+ ACHIEVEMENT_DOD_KILLS_WITH_AMERKNIFE,
+ ACHIEVEMENT_DOD_KILLS_WITH_SPADE,
+ ACHIEVEMENT_DOD_KILLS_WITH_PUNCH,
+ ACHIEVEMENT_DOD_KILLS_WITH_FRAG_US,
+ ACHIEVEMENT_DOD_KILLS_WITH_FRAG_GER,
+ ACHIEVEMENT_DOD_KILLS_WITH_RIFLEGREN_US,
+ ACHIEVEMENT_DOD_KILLS_WITH_RIFLEGREN_GER,
+
+ ACHIEVEMENT_DOD_CAPTURE_GRIND,
+ ACHIEVEMENT_DOD_BLOCK_CAPTURES_GRIND,
+ ACHIEVEMENT_DOD_ROUNDS_WON_GRIND,
+
+ ACHIEVEMENT_DOD_BOMBS_PLANTED_GRIND,
+ ACHIEVEMENT_DOD_BOMBS_DEFUSED_GRIND,
+
+ ACHIEVEMENT_DOD_ALL_PACK_1,
+
+ ACHIEVEMENT_DOD_BEAT_THE_HEAT,
+
+ // Winter 2011
+ ACHIEVEMENT_DOD_COLLECT_HOLIDAY_GIFTS,
+
+ NUM_DOD_ACHIEVEMENTS
+};
+
+#define ACHIEVEMENT_NUM_CONSECUTIVE_HEADSHOTS 5
+#define ACHIEVEMENT_MG_STREAK_IS_DOMINATING 8
+#define ACHIEVEMENT_NUM_ENEMY_WPN_KILLS 5
+#define ACHIEVEMENT_LONG_RANGE_ROCKET_DIST 1200
+// other magic numbers exist inside the achievements themselves in achievements_dod.cpp
+
+enum
+{
+ DOD_MUZZLEFLASH_PISTOL = 0,
+ DOD_MUZZLEFLASH_AUTO,
+ DOD_MUZZLEFLASH_RIFLE,
+ DOD_MUZZLEFLASH_MG,
+ DOD_MUZZLEFLASH_ROCKET,
+ DOD_MUZZLEFLASH_MG42
+};
+
+#define DOD_KILLS_DOMINATION 4
+
+// Death notice flags
+#define DOD_DEATHFLAG_DOMINATION 0x0001 // killer is dominating victim
+#define DOD_DEATHFLAG_REVENGE 0x0002 // killer got revenge on victim
+
+enum
+{
+ ACHIEVEMENT_AWARDS_NONE = 0,
+ ACHIEVEMENT_AWARDS_RIFLEMAN,
+ ACHIEVEMENT_AWARDS_ASSAULT,
+ ACHIEVEMENT_AWARDS_SUPPORT,
+ ACHIEVEMENT_AWARDS_SNIPER,
+ ACHIEVEMENT_AWARDS_MG,
+ ACHIEVEMENT_AWARDS_ROCKET,
+ ACHIEVEMENT_AWARDS_ALL_PACK_1,
+
+ NUM_ACHIEVEMENT_AWARDS
+};
+
+extern const char *g_pszAchievementAwards[NUM_ACHIEVEMENT_AWARDS];
+extern const char *g_pszAchievementAwardMaterials_Allies[NUM_ACHIEVEMENT_AWARDS];
+extern const char *g_pszAchievementAwardMaterials_Axis[NUM_ACHIEVEMENT_AWARDS];
+
+enum DODStatType_t
+{
+ DODSTAT_PLAYTIME = 0,
+ DODSTAT_ROUNDSWON,
+ DODSTAT_ROUNDSLOST,
+ DODSTAT_KILLS,
+ DODSTAT_DEATHS,
+ DODSTAT_CAPTURES,
+ DODSTAT_BLOCKS,
+ DODSTAT_BOMBSPLANTED,
+ DODSTAT_BOMBSDEFUSED,
+ DODSTAT_DOMINATIONS,
+ DODSTAT_REVENGES,
+ DODSTAT_SHOTS_HIT,
+ DODSTAT_SHOTS_FIRED,
+ DODSTAT_HEADSHOTS,
+
+ DODSTAT_MAX
+};
+
+#define DODSTAT_FIRST DODSTAT_PLAYTIME
+
+typedef struct
+{
+ int m_iStat[DODSTAT_MAX];
+ bool m_bDirty[DODSTAT_MAX];
+
+} dod_stat_accumulator_t;
+
+#define NUM_DOD_PLAYERCLASSES 6
+
+#endif // DOD_SHAREDDEFS_H
diff --git a/game/shared/dod/dod_usermessages.cpp b/game/shared/dod/dod_usermessages.cpp
new file mode 100644
index 0000000..ad704aa
--- /dev/null
+++ b/game/shared/dod/dod_usermessages.cpp
@@ -0,0 +1,65 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "usermessages.h"
+#include "shake.h"
+#include "voice_gamemgr.h"
+
+// NVNT include to register in haptic user messages
+#include "haptics/haptic_msgs.h"
+
+void RegisterUserMessages()
+{
+ usermessages->Register( "Geiger", 1 ); // geiger info data
+ usermessages->Register( "Train", 1 ); // train control data
+ usermessages->Register( "HudText", -1 );
+ usermessages->Register( "SayText", -1 );
+ usermessages->Register( "TextMsg", -1 );
+ usermessages->Register( "ResetHUD", 1 ); // called every respawn
+ usermessages->Register( "GameTitle", 0 ); // show game title
+ usermessages->Register( "ItemPickup", -1 ); // for item history on screen
+ usermessages->Register( "ShowMenu", -1 ); // show hud menu
+ usermessages->Register( "Shake", 13 ); // shake view
+ usermessages->Register( "Fade", 10 ); // fade HUD in/out
+ usermessages->Register( "VGUIMenu", -1 ); // Show VGUI menu
+ usermessages->Register( "Rumble", 3 ); // Send a rumble to a controller
+ usermessages->Register( "CloseCaption", -1 ); // Show a caption (by string id number)(duration in 10th of a second)
+
+ usermessages->Register( "VoiceMask", VOICE_MAX_PLAYERS_DW*4 * 2 + 1 );
+ usermessages->Register( "RequestState", 0 );
+
+ usermessages->Register( "BarTime", -1 ); // For the C4 progress bar.
+ usermessages->Register( "Damage", -1 ); // for HUD damage indicators
+ usermessages->Register( "RadioText", -1 ); // for HUD damage indicators
+ usermessages->Register( "HintText", -1 ); // Displays hint text display
+ usermessages->Register( "KeyHintText", -1 ); // Displays hint text display
+
+ usermessages->Register( "ReloadEffect", 2 ); // a player reloading..
+ usermessages->Register( "PlayerAnimEvent", -1 ); // jumping, firing, reload, etc.
+
+ usermessages->Register( "HudMsg", -1 );
+
+ usermessages->Register( "VoiceSubtitle", 3 );
+ usermessages->Register( "HandSignalSubtitle", 2 );
+ usermessages->Register( "UpdateRadar", -1 );
+ usermessages->Register( "KillCam", -1 );
+ usermessages->Register( "DeathStats", 9 );
+
+ usermessages->Register( "AchievementEvent", -1 );
+ usermessages->Register( "DODPlayerStatsUpdate", -1 );
+
+ // Voting
+ usermessages->Register( "CallVoteFailed", -1 );
+ usermessages->Register( "VoteStart", -1 );
+ usermessages->Register( "VotePass", -1 );
+ usermessages->Register( "VoteFailed", 2 );
+ usermessages->Register( "VoteSetup", -1 ); // Initiates client-side voting UI
+
+ // NVNT register haptic user messages
+ RegisterHapticMessages();
+}
+
diff --git a/game/shared/dod/dod_viewmodel.cpp b/game/shared/dod/dod_viewmodel.cpp
new file mode 100644
index 0000000..d353a50
--- /dev/null
+++ b/game/shared/dod/dod_viewmodel.cpp
@@ -0,0 +1,151 @@
+
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+#include "cbase.h"
+#include "dod_viewmodel.h"
+
+#ifdef CLIENT_DLL
+#include "c_dod_player.h"
+#include "prediction.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+LINK_ENTITY_TO_CLASS( dod_viewmodel, CDODViewModel );
+
+IMPLEMENT_NETWORKCLASS_ALIASED( DODViewModel, DT_DODViewModel )
+
+BEGIN_NETWORK_TABLE( CDODViewModel, DT_DODViewModel )
+END_NETWORK_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+#ifdef CLIENT_DLL
+CDODViewModel::CDODViewModel() : m_LagAnglesHistory("CDODViewModel::m_LagAnglesHistory")
+{
+ m_vLagAngles.Init();
+ m_LagAnglesHistory.Setup( &m_vLagAngles, 0 );
+ m_vLoweredWeaponOffset.Init();
+}
+#else
+CDODViewModel::CDODViewModel()
+{
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CDODViewModel::~CDODViewModel()
+{
+}
+
+#ifdef CLIENT_DLL
+ConVar cl_wpn_sway_interp( "cl_wpn_sway_interp", "0.1", FCVAR_CLIENTDLL );
+ConVar cl_wpn_sway_scale( "cl_wpn_sway_scale", "2.6", FCVAR_CLIENTDLL );
+#endif
+
+void CDODViewModel::CalcViewModelLag( Vector& origin, QAngle& angles, QAngle& original_angles )
+{
+#ifdef CLIENT_DLL
+ if ( prediction->InPrediction() )
+ {
+ return;
+ }
+
+ float flSwayScale = cl_wpn_sway_scale.GetFloat();
+
+ CWeaponDODBase *pWeapon = dynamic_cast<CWeaponDODBase*>(GetWeapon());
+
+ if ( pWeapon )
+ {
+ flSwayScale *= pWeapon->GetViewModelSwayScale();
+ }
+
+ // Calculate our drift
+ Vector forward, right, up;
+ AngleVectors( angles, &forward, &right, &up );
+
+ // Add an entry to the history.
+ m_vLagAngles = angles;
+ m_LagAnglesHistory.NoteChanged( gpGlobals->curtime, cl_wpn_sway_interp.GetFloat(), false );
+
+ // Interpolate back 100ms.
+ m_LagAnglesHistory.Interpolate( gpGlobals->curtime, cl_wpn_sway_interp.GetFloat() );
+
+ // Now take the 100ms angle difference and figure out how far the forward vector moved in local space.
+ Vector vLaggedForward;
+ QAngle angleDiff = m_vLagAngles - angles;
+ AngleVectors( -angleDiff, &vLaggedForward, 0, 0 );
+ Vector vForwardDiff = Vector(1,0,0) - vLaggedForward;
+
+ // Now offset the origin using that.
+ vForwardDiff *= flSwayScale;
+ origin += forward*vForwardDiff.x + right*-vForwardDiff.y + up*vForwardDiff.z;
+#endif
+}
+
+#ifdef CLIENT_DLL
+ConVar cl_gunlowerangle( "cl_gunlowerangle", "30", FCVAR_CLIENTDLL );
+ConVar cl_gunlowerspeed( "cl_gunlowerspeed", "2", FCVAR_CLIENTDLL );
+
+ConVar cl_test_vm_offset( "cl_test_vm_offset", "0 0 0", FCVAR_CHEAT | FCVAR_CLIENTDLL );
+#endif
+
+void CDODViewModel::CalcViewModelView( CBasePlayer *owner, const Vector& eyePosition, const QAngle& eyeAngles )
+{
+#if defined( CLIENT_DLL )
+
+ Vector vecNewOrigin = eyePosition;
+ QAngle vecNewAngles = eyeAngles;
+
+ // Check for lowering the weapon
+ C_DODPlayer *pPlayer = ToDODPlayer( owner );
+
+ Assert( pPlayer );
+
+ bool bLowered = pPlayer->IsWeaponLowered();
+
+ QAngle vecLoweredAngles(0,0,0);
+
+ m_vLoweredWeaponOffset.x = Approach( bLowered ? cl_gunlowerangle.GetFloat() : 0, m_vLoweredWeaponOffset.x, cl_gunlowerspeed.GetFloat() );
+ vecLoweredAngles.x += m_vLoweredWeaponOffset.x;
+
+ vecNewAngles += vecLoweredAngles;
+
+ Vector forward, right, up;
+ AngleVectors( vecNewAngles, &forward, &right, &up );
+
+ Vector test;
+ const char *szTestOffset = cl_test_vm_offset.GetString();
+ sscanf( szTestOffset, " %f %f %f", &test[0], &test[1], &test[2] );
+
+ // cvar cl_test_vm_offset overrides calculated view model offset
+ if ( test.Length() > 0 )
+ {
+ vecNewOrigin += forward * test[0] + right * test[1] + up * test[2];
+ }
+ else
+ {
+ // Move the view model origin between the script standing and prone position
+ // based on the current view height
+ CWeaponDODBase *pWeapon = dynamic_cast<CWeaponDODBase*>(GetWeapon());
+
+ if ( pWeapon )
+ {
+ Vector offset = pWeapon->GetDesiredViewModelOffset( pPlayer );
+
+ // add our offset in the proper direction
+ vecNewOrigin += forward * offset[0] + right * offset[1] + up * offset[2];
+ }
+ }
+
+ BaseClass::CalcViewModelView( owner, vecNewOrigin, vecNewAngles );
+
+#endif
+} \ No newline at end of file
diff --git a/game/shared/dod/dod_viewmodel.h b/game/shared/dod/dod_viewmodel.h
new file mode 100644
index 0000000..4192a78
--- /dev/null
+++ b/game/shared/dod/dod_viewmodel.h
@@ -0,0 +1,60 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef DOD_VIEWMODEL_H
+#define DOD_VIEWMODEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "predictable_entity.h"
+#include "utlvector.h"
+#include "baseplayer_shared.h"
+#include "shared_classnames.h"
+
+#if defined( CLIENT_DLL )
+#define CDODViewModel C_DODViewModel
+#endif
+
+class CDODViewModel : public CBaseViewModel
+{
+ DECLARE_CLASS( CDODViewModel, CBaseViewModel );
+public:
+
+ DECLARE_NETWORKCLASS();
+
+ CDODViewModel( void );
+ ~CDODViewModel( void );
+
+ virtual void CalcViewModelLag( Vector& origin, QAngle& angles, QAngle& original_angles );
+ virtual void CalcViewModelView( CBasePlayer *owner, const Vector& eyePosition, const QAngle& eyeAngles );
+
+#if defined( CLIENT_DLL )
+ virtual bool ShouldPredict( void )
+ {
+ if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() )
+ return true;
+
+ return BaseClass::ShouldPredict();
+ }
+#endif
+
+private:
+
+#if defined( CLIENT_DLL )
+
+ // This is used to lag the angles.
+ CInterpolatedVar<QAngle> m_LagAnglesHistory;
+ QAngle m_vLagAngles;
+
+ CDODViewModel( const CDODViewModel & ); // not defined, not accessible
+
+ QAngle m_vLoweredWeaponOffset;
+#endif
+};
+
+#endif // DOD_VIEWMODEL_H
diff --git a/game/shared/dod/dod_weapon_parse.cpp b/game/shared/dod/dod_weapon_parse.cpp
new file mode 100644
index 0000000..35d7183
--- /dev/null
+++ b/game/shared/dod/dod_weapon_parse.cpp
@@ -0,0 +1,195 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include <KeyValues.h>
+#include "dod_weapon_parse.h"
+#include "dod_shareddefs.h"
+
+// criteria that we parse out of the file.
+// tells us which player animation states
+// should use the alternate wpn p model
+static struct
+{
+ const char *m_pCriteriaName;
+ int m_iFlagValue;
+} g_AltWpnCritera[] =
+{
+ { "ALTWPN_CRITERIA_FIRING", ALTWPN_CRITERIA_FIRING },
+ { "ALTWPN_CRITERIA_RELOADING", ALTWPN_CRITERIA_RELOADING },
+ { "ALTWPN_CRITERIA_DEPLOYED", ALTWPN_CRITERIA_DEPLOYED },
+ { "ALTWPN_CRITERIA_DEPLOYED_RELOAD", ALTWPN_CRITERIA_DEPLOYED_RELOAD },
+ { "ALTWPN_CRITERIA_PRONE_DEPLOYED_RELOAD", ALTWPN_CRITERIA_PRONE_DEPLOYED_RELOAD }
+};
+
+FileWeaponInfo_t* CreateWeaponInfo()
+{
+ return new CDODWeaponInfo;
+}
+
+
+CDODWeaponInfo::CDODWeaponInfo()
+{
+ m_szReloadModel[0] = '\0';
+ m_szDeployedModel[0] = '\0';
+ m_szDeployedReloadModel[0] = '\0';
+ m_szProneDeployedReloadModel[0] = '\0';
+}
+
+
+void CDODWeaponInfo::Parse( KeyValues *pKeyValuesData, const char *szWeaponName )
+{
+ BaseClass::Parse( pKeyValuesData, szWeaponName );
+
+ m_iCrosshairMinDistance = pKeyValuesData->GetInt( "CrosshairMinDistance", 4 );
+ m_iCrosshairDeltaDistance = pKeyValuesData->GetInt( "CrosshairDeltaDistance", 3 );
+ m_iMuzzleFlashType = pKeyValuesData->GetFloat( "MuzzleFlashType", 0 );
+ m_flMuzzleFlashScale = pKeyValuesData->GetFloat( "MuzzleFlashScale", 0.5 );
+
+ m_iDamage = pKeyValuesData->GetInt( "Damage", 1 );
+ m_flAccuracy = pKeyValuesData->GetFloat( "Accuracy", 1.0 );
+ m_flSecondaryAccuracy = pKeyValuesData->GetFloat( "SecondaryAccuracy", 1.0 );
+ m_flAccuracyMovePenalty = pKeyValuesData->GetFloat( "AccuracyMovePenalty", 0.1 );
+ m_flRecoil = pKeyValuesData->GetFloat( "Recoil", 99.0 );
+ m_flPenetration = pKeyValuesData->GetFloat( "Penetration", 1.0 );
+ m_flFireDelay = pKeyValuesData->GetFloat( "FireDelay", 0.1 );
+ m_flSecondaryFireDelay = pKeyValuesData->GetFloat( "SecondaryFireDelay", 0.1 );
+ m_flTimeToIdleAfterFire = pKeyValuesData->GetFloat( "IdleTimeAfterFire", 1.0 );
+ m_flIdleInterval = pKeyValuesData->GetFloat( "IdleInterval", 1.0 );
+ m_bCanDrop = ( pKeyValuesData->GetInt( "CanDrop", 1 ) > 0 );
+ m_iBulletsPerShot = pKeyValuesData->GetInt( "BulletsPerShot", 1 );
+
+ m_iHudClipHeight = pKeyValuesData->GetInt( "HudClipHeight", 0 );
+ m_iHudClipBaseHeight = pKeyValuesData->GetInt( "HudClipBaseHeight", 0 );
+ m_iHudClipBulletHeight = pKeyValuesData->GetInt( "HudClipBulletHeight", 0 );
+
+ m_iAmmoPickupClips = pKeyValuesData->GetInt( "AmmoPickupClips", 2 );
+
+ m_iDefaultAmmoClips = pKeyValuesData->GetInt( "DefaultAmmoClips", 0 );
+
+ m_flViewModelFOV = pKeyValuesData->GetFloat( "ViewModelFOV", 90.0f );
+
+// const char *pAnimEx = pKeyValuesData->GetString( "PlayerAnimationExtension", "error" );
+// Q_strncpy( m_szAnimExtension, pAnimEx, sizeof( m_szAnimExtension ) );
+
+ // if this key exists, use this for reload animations instead of anim_prefix
+// Q_strncpy( m_szReloadAnimPrefix, pKeyValuesData->GetString( "reload_anim_prefix", "" ), MAX_WEAPON_PREFIX );
+
+ m_flBotAudibleRange = pKeyValuesData->GetFloat( "BotAudibleRange", 2000.0f );
+
+ m_iTracerType = pKeyValuesData->GetInt( "Tracer", 0 );
+
+ //Weapon Type
+ const char *pTypeString = pKeyValuesData->GetString( "WeaponType", NULL );
+
+ m_WeaponType = WPN_TYPE_UNKNOWN;
+ if ( !pTypeString )
+ {
+ Assert( false );
+ }
+ else if ( Q_stricmp( pTypeString, "Melee" ) == 0 )
+ {
+ m_WeaponType = WPN_TYPE_MELEE;
+ }
+ else if ( Q_stricmp( pTypeString, "Camera" ) == 0 )
+ {
+ m_WeaponType = WPN_TYPE_CAMERA;
+ }
+ else if ( Q_stricmp( pTypeString, "Grenade" ) == 0 )
+ {
+ m_WeaponType = WPN_TYPE_GRENADE;
+ }
+ else if ( Q_stricmp( pTypeString, "Pistol" ) == 0 )
+ {
+ m_WeaponType = WPN_TYPE_PISTOL;
+ }
+ else if ( Q_stricmp( pTypeString, "Rifle" ) == 0 )
+ {
+ m_WeaponType = WPN_TYPE_RIFLE;
+ }
+ else if ( Q_stricmp( pTypeString, "Sniper" ) == 0 )
+ {
+ m_WeaponType = WPN_TYPE_SNIPER;
+ }
+ else if ( Q_stricmp( pTypeString, "SubMG" ) == 0 )
+ {
+ m_WeaponType = WPN_TYPE_SUBMG;
+ }
+ else if ( Q_stricmp( pTypeString, "MG" ) == 0 )
+ {
+ m_WeaponType = WPN_TYPE_MG;
+ }
+ else if ( Q_stricmp( pTypeString, "Bazooka" ) == 0 )
+ {
+ m_WeaponType = WPN_TYPE_BAZOOKA;
+ }
+ else if ( Q_stricmp( pTypeString, "Bandage" ) == 0 )
+ {
+ m_WeaponType = WPN_TYPE_BANDAGE;
+ }
+ else if ( Q_stricmp( pTypeString, "Sidearm" ) == 0 )
+ {
+ m_WeaponType = WPN_TYPE_SIDEARM;
+ }
+ else if ( Q_stricmp( pTypeString, "RifleGrenade" ) == 0 )
+ {
+ m_WeaponType = WPN_TYPE_RIFLEGRENADE;
+ }
+ else if ( Q_stricmp( pTypeString, "Bomb" ) == 0 )
+ {
+ m_WeaponType = WPN_TYPE_BOMB;
+ }
+ else
+ {
+ Assert( false );
+ }
+
+ Q_strncpy( m_szReloadModel, pKeyValuesData->GetString( "reloadmodel" ), sizeof( m_szReloadModel ) );
+ Q_strncpy( m_szDeployedModel, pKeyValuesData->GetString( "deployedmodel" ), sizeof( m_szDeployedModel ) );
+ Q_strncpy( m_szDeployedReloadModel, pKeyValuesData->GetString( "deployedreloadmodel" ), sizeof( m_szDeployedReloadModel ) );
+ Q_strncpy( m_szProneDeployedReloadModel, pKeyValuesData->GetString( "pronedeployedreloadmodel" ), sizeof( m_szProneDeployedReloadModel ) );
+
+
+ m_iAltWpnCriteria = ALTWPN_CRITERIA_NONE;
+
+ for ( int i=0; i < ARRAYSIZE( g_AltWpnCritera ); i++ )
+ {
+ int iVal = pKeyValuesData->GetInt( g_AltWpnCritera[i].m_pCriteriaName, 0 );
+ if ( iVal == 1 )
+ {
+ m_iAltWpnCriteria |= g_AltWpnCritera[i].m_iFlagValue;
+ }
+ }
+
+ const char *szNormalOffset = pKeyValuesData->GetString( "vm_normal_offset", "0 0 0" );
+ const char *szProneOffset = pKeyValuesData->GetString( "vm_prone_offset", "0 0 0" );
+ const char *szIronSightOffset = pKeyValuesData->GetString( "vm_ironsight_offset", "0 0 0" );
+
+ sscanf( szNormalOffset, "%f %f %f", &m_vecViewNormalOffset[0], &m_vecViewNormalOffset[1], &m_vecViewNormalOffset[2]);
+ sscanf( szProneOffset, "%f %f %f", &m_vecViewProneOffset[0], &m_vecViewProneOffset[1], &m_vecViewProneOffset[2]);
+ sscanf( szIronSightOffset, "%f %f %f", &m_vecIronSightOffset[0], &m_vecIronSightOffset[1], &m_vecIronSightOffset[2]);
+
+ m_iDefaultTeam = TEAM_ALLIES;
+
+ const char *pDefaultTeam = pKeyValuesData->GetString( "default_team", NULL );
+
+ if ( pDefaultTeam )
+ {
+ if ( FStrEq( pDefaultTeam, "Axis" ) )
+ {
+ m_iDefaultTeam = TEAM_AXIS;
+ }
+ else if ( FStrEq( pDefaultTeam, "Allies" ) )
+ {
+ m_iDefaultTeam = TEAM_ALLIES;
+ }
+ else
+ {
+ Assert( !"invalid param to \"default_team\" in weapon scripts\n" );
+ }
+ }
+}
+
diff --git a/game/shared/dod/dod_weapon_parse.h b/game/shared/dod/dod_weapon_parse.h
new file mode 100644
index 0000000..a42eb42
--- /dev/null
+++ b/game/shared/dod/dod_weapon_parse.h
@@ -0,0 +1,103 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef DOD_WEAPON_PARSE_H
+#define DOD_WEAPON_PARSE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "weapon_parse.h"
+#include "networkvar.h"
+
+#define WPN_TYPE_MELEE (1<<0)
+#define WPN_TYPE_GRENADE (1<<1)
+//#define WPN_TYPE_GRENADE_LIVE (1<<2) //exploding grenades, unused
+#define WPN_TYPE_PISTOL (1<<3)
+#define WPN_TYPE_RIFLE (1<<4)
+#define WPN_TYPE_SNIPER (1<<5)
+#define WPN_TYPE_SUBMG (1<<6)
+#define WPN_TYPE_MG (1<<7) //mg42, 30cal
+#define WPN_TYPE_BAZOOKA (1<<8)
+#define WPN_TYPE_BANDAGE (1<<9)
+#define WPN_TYPE_SIDEARM (1<<10) //carbine - secondary weapons
+#define WPN_TYPE_RIFLEGRENADE (1<<11)
+#define WPN_TYPE_BOMB (1<<12)
+#define WPN_TYPE_UNKNOWN (1<<13)
+#define WPN_TYPE_CAMERA (1<<12)
+
+#define WPN_MASK_GUN ( WPN_TYPE_PISTOL | WPN_TYPE_RIFLE | WPN_TYPE_SNIPER | WPN_TYPE_SUBMG | WPN_TYPE_MG | WPN_TYPE_SIDEARM )
+
+//--------------------------------------------------------------------------------------------------------
+class CDODWeaponInfo : public FileWeaponInfo_t
+{
+public:
+ DECLARE_CLASS_GAMEROOT( CDODWeaponInfo, FileWeaponInfo_t );
+
+ CDODWeaponInfo();
+
+ virtual void Parse( ::KeyValues *pKeyValuesData, const char *szWeaponName );
+
+ int m_iDamage;
+ int m_flPenetration;
+ int m_iBulletsPerShot;
+ int m_iMuzzleFlashType;
+ float m_flMuzzleFlashScale;
+
+ bool m_bCanDrop;
+
+ float m_flRecoil;
+
+ float m_flRange;
+ float m_flRangeModifier;
+
+ float m_flAccuracy;
+ float m_flSecondaryAccuracy;
+ float m_flAccuracyMovePenalty;
+
+ float m_flFireDelay;
+ float m_flSecondaryFireDelay;
+
+ int m_iCrosshairMinDistance;
+ int m_iCrosshairDeltaDistance;
+
+ int m_WeaponType;
+
+ float m_flBotAudibleRange;
+
+ char m_szReloadModel[MAX_WEAPON_STRING];
+ char m_szDeployedModel[MAX_WEAPON_STRING];
+ char m_szDeployedReloadModel[MAX_WEAPON_STRING];
+ char m_szProneDeployedReloadModel[MAX_WEAPON_STRING];
+
+ //timers
+ float m_flTimeToIdleAfterFire; //wait this long until idling after fire
+ float m_flIdleInterval; //wait this long after idling to idle again
+
+ //ammo
+ int m_iDefaultAmmoClips;
+ int m_iAmmoPickupClips;
+
+ int m_iHudClipHeight;
+ int m_iHudClipBaseHeight;
+ int m_iHudClipBulletHeight;
+
+ int m_iTracerType;
+
+ float m_flViewModelFOV;
+
+ int m_iAltWpnCriteria;
+
+ Vector m_vecViewNormalOffset;
+ Vector m_vecViewProneOffset;
+ Vector m_vecIronSightOffset;
+
+ int m_iDefaultTeam;
+};
+
+
+#endif // DOD_WEAPON_PARSE_H
diff --git a/game/shared/dod/fx_dod_shared.cpp b/game/shared/dod/fx_dod_shared.cpp
new file mode 100644
index 0000000..1590012
--- /dev/null
+++ b/game/shared/dod/fx_dod_shared.cpp
@@ -0,0 +1,370 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "fx_dod_shared.h"
+#include "weapon_dodbase.h"
+#include "engine/ivdebugoverlay.h"
+
+#ifndef CLIENT_DLL
+ #include "ilagcompensationmanager.h"
+#endif
+
+#ifndef CLIENT_DLL
+
+//=============================================================================
+//
+// Explosions.
+//
+class CTEDODExplosion : public CBaseTempEntity
+{
+public:
+
+ DECLARE_CLASS( CTEDODExplosion, CBaseTempEntity );
+ DECLARE_SERVERCLASS();
+
+ CTEDODExplosion( const char *name );
+
+public:
+
+ Vector m_vecOrigin;
+ Vector m_vecNormal;
+};
+
+// Singleton to fire explosion objects
+static CTEDODExplosion g_TEDODExplosion( "DODExplosion" );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+//-----------------------------------------------------------------------------
+CTEDODExplosion::CTEDODExplosion( const char *name ) : CBaseTempEntity( name )
+{
+ m_vecOrigin.Init();
+ m_vecNormal.Init();
+}
+
+IMPLEMENT_SERVERCLASS_ST( CTEDODExplosion, DT_TEDODExplosion )
+ SendPropFloat( SENDINFO_NOCHECK( m_vecOrigin[0] ), -1, SPROP_COORD_MP_INTEGRAL ),
+ SendPropFloat( SENDINFO_NOCHECK( m_vecOrigin[1] ), -1, SPROP_COORD_MP_INTEGRAL ),
+ SendPropFloat( SENDINFO_NOCHECK( m_vecOrigin[2] ), -1, SPROP_COORD_MP_INTEGRAL ),
+ SendPropVector( SENDINFO_NOCHECK( m_vecNormal ), 6, 0, -1.0f, 1.0f ),
+END_SEND_TABLE()
+
+void TE_DODExplosion( IRecipientFilter &filter, float flDelay, const Vector &vecOrigin, const Vector &vecNormal )
+{
+ VectorCopy( vecOrigin, g_TEDODExplosion.m_vecOrigin );
+ VectorCopy( vecNormal, g_TEDODExplosion.m_vecNormal );
+
+ // Send it over the wire
+ g_TEDODExplosion.Create( filter, flDelay );
+}
+
+#endif
+
+#ifdef CLIENT_DLL
+
+ #include "fx_impact.h"
+
+ extern void FX_TracerSound( const Vector &start, const Vector &end, int iTracerType );
+
+ // this is a cheap ripoff from CBaseCombatWeapon::WeaponSound():
+ void FX_WeaponSound(
+ int iPlayerIndex,
+ WeaponSound_t sound_type,
+ const Vector &vOrigin,
+ CDODWeaponInfo *pWeaponInfo )
+ {
+
+ // If we have some sounds from the weapon classname.txt file, play a random one of them
+ const char *shootsound = pWeaponInfo->aShootSounds[ sound_type ];
+ if ( !shootsound || !shootsound[0] )
+ return;
+
+ CBroadcastRecipientFilter filter; // this is client side only
+
+ if ( !te->CanPredict() )
+ return;
+
+ CBaseEntity::EmitSound( filter, iPlayerIndex, shootsound, &vOrigin );
+ }
+
+ class CGroupedSound
+ {
+ public:
+ string_t m_SoundName;
+ Vector m_vPos;
+ };
+
+ CUtlVector<CGroupedSound> g_GroupedSounds;
+
+
+ // Called by the ImpactSound function.
+ void ShotgunImpactSoundGroup( const char *pSoundName, const Vector &vEndPos )
+ {
+ // Don't play the sound if it's too close to another impact sound.
+ for ( int i=0; i < g_GroupedSounds.Count(); i++ )
+ {
+ CGroupedSound *pSound = &g_GroupedSounds[i];
+
+ if ( vEndPos.DistToSqr( pSound->m_vPos ) < 300*300 )
+ {
+ if ( Q_stricmp( pSound->m_SoundName, pSoundName ) == 0 )
+ return;
+ }
+ }
+
+ // Ok, play the sound and add it to the list.
+ CLocalPlayerFilter filter;
+ C_BaseEntity::EmitSound( filter, NULL, pSoundName, &vEndPos );
+
+ int tail = g_GroupedSounds.AddToTail();
+ g_GroupedSounds[tail].m_SoundName = pSoundName;
+ g_GroupedSounds[tail].m_vPos = vEndPos;
+ }
+
+
+ void StartGroupingSounds()
+ {
+ Assert( g_GroupedSounds.Count() == 0 );
+ SetImpactSoundRoute( ShotgunImpactSoundGroup );
+ }
+
+
+ void EndGroupingSounds()
+ {
+ g_GroupedSounds.Purge();
+ SetImpactSoundRoute( NULL );
+ }
+
+#else
+
+ #include "te_firebullets.h"
+
+ // Server doesn't play sounds anyway.
+ void StartGroupingSounds() {}
+ void EndGroupingSounds() {}
+ void FX_WeaponSound ( int iPlayerIndex,
+ WeaponSound_t sound_type,
+ const Vector &vOrigin,
+ CDODWeaponInfo *pWeaponInfo ) {};
+
+#endif
+
+
+
+// This runs on both the client and the server.
+// On the server, it only does the damage calculations.
+// On the client, it does all the effects.
+void FX_FireBullets(
+ int iPlayerIndex,
+ const Vector &vOrigin,
+ const QAngle &vAngles,
+ int iWeaponID,
+ int iMode,
+ int iSeed,
+ float flSpread
+ )
+{
+ bool bDoEffects = true;
+
+#ifdef CLIENT_DLL
+ C_DODPlayer *pPlayer = ToDODPlayer( ClientEntityList().GetBaseEntity( iPlayerIndex ) );
+#else
+ CDODPlayer *pPlayer = ToDODPlayer( UTIL_PlayerByIndex( iPlayerIndex) );
+#endif
+
+ const char * weaponAlias = WeaponIDToAlias( iWeaponID );
+
+ if ( !weaponAlias )
+ {
+ DevMsg("FX_FireBullets: weapon alias for ID %i not found\n", iWeaponID );
+ return;
+ }
+
+ //MATTTODO: Why are we looking up the weapon info again when every weapon
+ // stores its own m_pWeaponInfo pointer?
+
+ char wpnName[128];
+ Q_snprintf( wpnName, sizeof( wpnName ), "weapon_%s", weaponAlias );
+ WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( wpnName );
+
+ if ( hWpnInfo == GetInvalidWeaponInfoHandle() )
+ {
+ DevMsg("FX_FireBullets: LookupWeaponInfoSlot failed for weapon %s\n", wpnName );
+ return;
+ }
+
+ CDODWeaponInfo *pWeaponInfo = static_cast< CDODWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
+
+#ifdef CLIENT_DLL
+ if( pPlayer && !pPlayer->IsDormant() )
+ pPlayer->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN );
+#else
+ if( pPlayer )
+ pPlayer->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN );
+#endif
+
+#ifndef CLIENT_DLL
+ // if this is server code, send the effect over to client as temp entity
+ // Dispatch one message for all the bullet impacts and sounds.
+ TE_FireBullets(
+ iPlayerIndex,
+ vOrigin,
+ vAngles,
+ iWeaponID,
+ iMode,
+ iSeed,
+ flSpread
+ );
+
+ bDoEffects = false; // no effects on server
+
+ // Let the player remember the usercmd he fired a weapon on. Assists in making decisions about lag compensation.
+ pPlayer->NoteWeaponFired();
+#endif
+
+
+
+ WeaponSound_t sound_type = SINGLE;
+
+ if ( bDoEffects)
+ {
+ FX_WeaponSound( iPlayerIndex, sound_type, vOrigin, pWeaponInfo );
+ }
+
+ // Fire bullets, calculate impacts & effects
+ if ( !pPlayer )
+ return;
+
+ StartGroupingSounds();
+
+#if !defined (CLIENT_DLL)
+ // Move other players back to history positions based on local player's lag
+ lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() );
+#endif
+
+ RandomSeed( iSeed );
+
+ float x, y;
+ do
+ {
+ x = random->RandomFloat( -0.5, 0.5 ) + random->RandomFloat( -0.5, 0.5 );
+ y = random->RandomFloat( -0.5, 0.5 ) + random->RandomFloat( -0.5, 0.5 );
+ } while ( (x * x + y * y) > 1.0f );
+
+ Vector vecForward, vecRight, vecUp;
+ AngleVectors( vAngles, &vecForward, &vecRight, &vecUp );
+
+ Vector vecDirShooting = vecForward +
+ x * flSpread * vecRight +
+ y * flSpread * vecUp;
+
+ vecDirShooting.NormalizeInPlace();
+
+ FireBulletsInfo_t info( 1 /*shots*/, vOrigin, vecDirShooting, Vector( flSpread, flSpread, FLOAT32_NAN), MAX_COORD_RANGE, pWeaponInfo->iAmmoType );
+ info.m_flDamage = pWeaponInfo->m_iDamage;
+ info.m_pAttacker = pPlayer;
+
+ pPlayer->FireBullets( info );
+
+#ifdef CLIENT_DLL
+
+ {
+ trace_t tr;
+ UTIL_TraceLine( vOrigin, vOrigin + vecDirShooting * MAX_COORD_RANGE, MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &tr );
+
+ // if this is a local player, start at attachment on view model
+ // else start on attachment on weapon model
+
+ int iEntIndex = pPlayer->entindex();
+ int iAttachment = 1;
+
+ Vector vecStart = tr.startpos;
+ QAngle angAttachment;
+
+ C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
+
+ bool bInToolRecordingMode = clienttools->IsInRecordingMode();
+
+ // try to align tracers to actual weapon barrel if possible
+ if ( pPlayer->IsLocalPlayer() && !bInToolRecordingMode )
+ {
+ C_BaseViewModel *pViewModel = pPlayer->GetViewModel(0);
+
+ if ( pViewModel )
+ {
+ iEntIndex = pViewModel->entindex();
+ pViewModel->GetAttachment( iAttachment, vecStart, angAttachment );
+ }
+ }
+ else if ( pLocalPlayer &&
+ pLocalPlayer->GetObserverTarget() == pPlayer &&
+ pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE )
+ {
+ // get our observer target's view model
+
+ C_BaseViewModel *pViewModel = pLocalPlayer->GetViewModel(0);
+
+ if ( pViewModel )
+ {
+ iEntIndex = pViewModel->entindex();
+ pViewModel->GetAttachment( iAttachment, vecStart, angAttachment );
+ }
+ }
+ else if ( !pPlayer->IsDormant() )
+ {
+ // fill in with third person weapon model index
+ C_BaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon();
+
+ if( pWeapon )
+ {
+ iEntIndex = pWeapon->entindex();
+
+ int nModelIndex = pWeapon->GetModelIndex();
+ int nWorldModelIndex = pWeapon->GetWorldModelIndex();
+ if ( bInToolRecordingMode && nModelIndex != nWorldModelIndex )
+ {
+ pWeapon->SetModelIndex( nWorldModelIndex );
+ }
+
+ pWeapon->GetAttachment( iAttachment, vecStart, angAttachment );
+
+ if ( bInToolRecordingMode && nModelIndex != nWorldModelIndex )
+ {
+ pWeapon->SetModelIndex( nModelIndex );
+ }
+ }
+ }
+
+ switch( pWeaponInfo->m_iTracerType )
+ {
+ case 1: // Machine gun, heavy tracer
+ UTIL_Tracer( vecStart, tr.endpos, iEntIndex, TRACER_DONT_USE_ATTACHMENT, 5000.0, true, "BrightTracer" );
+ break;
+
+ case 2: // rifle, smg, light tracer
+ vecStart += vecDirShooting * 150;
+ UTIL_Tracer( vecStart, tr.endpos, iEntIndex, TRACER_DONT_USE_ATTACHMENT, 5000.0, true, "FaintTracer" );
+ break;
+
+ case 0: // pistols etc, just do the sound
+ {
+ FX_TracerSound( vecStart, tr.endpos, TRACER_TYPE_DEFAULT );
+ }
+ default:
+ break;
+ }
+ }
+#endif
+
+#if !defined (CLIENT_DLL)
+ lagcompensation->FinishLagCompensation( pPlayer );
+#endif
+
+ EndGroupingSounds();
+}
+
diff --git a/game/shared/dod/fx_dod_shared.h b/game/shared/dod/fx_dod_shared.h
new file mode 100644
index 0000000..2d74124
--- /dev/null
+++ b/game/shared/dod/fx_dod_shared.h
@@ -0,0 +1,44 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef FX_DOD_SHARED_H
+#define FX_DOD_SHARED_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#ifdef CLIENT_DLL
+ #include "c_dod_player.h"
+#else
+ #include "dod_player.h"
+#endif
+
+#include "dod_weapon_parse.h"
+
+
+// This runs on both the client and the server.
+// On the server, it only does the damage calculations.
+// On the client, it does all the effects.
+void FX_FireBullets(
+ int iPlayer,
+ const Vector &vOrigin,
+ const QAngle &vAngles,
+ int iWeaponID,
+ int iMode,
+ int iSeed,
+ float flSpread
+ );
+
+
+#ifndef CLIENT_DLL
+
+ void TE_DODExplosion( IRecipientFilter &filter, float flDelay, const Vector &vecOrigin, const Vector &vecNormal );
+
+#endif
+
+
+#endif // FX_DOD_SHARED_H
diff --git a/game/shared/dod/weapon_30cal.cpp b/game/shared/dod/weapon_30cal.cpp
new file mode 100644
index 0000000..919f9f7
--- /dev/null
+++ b/game/shared/dod/weapon_30cal.cpp
@@ -0,0 +1,423 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbipodgun.h"
+
+#if defined( CLIENT_DLL )
+
+ #include "c_dod_player.h"
+
+ #define CWeapon30cal C_Weapon30cal
+
+#else
+
+ #include "dod_player.h"
+
+#endif
+
+
+class CWeapon30cal : public CDODBipodWeapon
+{
+public:
+ DECLARE_CLASS( CWeapon30cal, CDODBipodWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeapon30cal() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_30CAL; }
+
+ // weapon id for stats purposes
+ virtual DODWeaponID GetStatsWeaponID( void )
+ {
+ if ( !IsDeployed() )
+ return WEAPON_30CAL_UNDEPLOYED;
+ else
+ return WEAPON_30CAL;
+ }
+
+ virtual void PrimaryAttack( void );
+
+ virtual bool ShouldDrawCrosshair( void ) { return IsDeployed(); }
+
+ virtual bool Reload( void );
+
+ virtual Activity GetDrawActivity( void );
+ virtual Activity GetDeployActivity( void );
+ virtual Activity GetUndeployActivity( void );
+ virtual Activity GetIdleActivity( void );
+ virtual Activity GetPrimaryAttackActivity( void );
+
+ virtual float GetRecoil( void );
+
+private:
+ CWeapon30cal( const CWeapon30cal & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( Weapon30cal, DT_Weapon30cal )
+
+BEGIN_NETWORK_TABLE( CWeapon30cal, DT_Weapon30cal )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeapon30cal )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_30cal, CWeapon30cal );
+PRECACHE_WEAPON_REGISTER( weapon_30cal );
+
+acttable_t CWeapon30cal::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_30CAL, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_30CAL, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_30CAL, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_30CAL, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_30CAL, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_30CAL, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_30CAL, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_30CAL, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_30CAL, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_30CAL, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_30CAL, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_30CAL, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_30CAL, false },
+
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_30CAL, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_30CAL, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_30CAL, false },
+ { ACT_DOD_DEPLOYED, ACT_DOD_DEPLOY_30CAL, false },
+ { ACT_DOD_PRONE_DEPLOYED, ACT_DOD_PRONE_DEPLOY_30CAL, false },
+ { ACT_DOD_PRIMARYATTACK_DEPLOYED, ACT_DOD_PRIMARYATTACK_DEPLOYED_30CAL, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED, ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED_30CAL,false },
+ { ACT_DOD_RELOAD_DEPLOYED, ACT_DOD_RELOAD_DEPLOYED_30CAL, false },
+ { ACT_DOD_RELOAD_PRONE_DEPLOYED, ACT_DOD_RELOAD_PRONE_DEPLOYED_30CAL, false },
+
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_30CAL, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_30CAL, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeapon30cal );
+
+bool CWeapon30cal::Reload( void )
+{
+ if( !IsDeployed() )
+ {
+#ifdef CLIENT_DLL
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+ if ( pPlayer )
+ pPlayer->HintMessage( HINT_MG_DEPLOY_TO_RELOAD );
+#endif
+ return false;
+ }
+
+ return BaseClass::Reload();
+}
+
+void CWeapon30cal::PrimaryAttack( void )
+{
+ if ( m_iClip1 <= 0 )
+ {
+ if (m_bFireOnEmpty)
+ {
+ PlayEmptySound();
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
+ }
+
+ return;
+ }
+
+#ifdef CLIENT_DLL
+ C_DODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+#else
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+#endif
+
+ Assert( pPlayer );
+
+ if( !IsDeployed() )
+ {
+#ifdef CLIENT_DLL
+ pPlayer->HintMessage( HINT_MG_FIRE_UNDEPLOYED );
+#endif
+ pPlayer->m_Shared.SetSlowedTime( 0.2 );
+
+ float flStamina = pPlayer->m_Shared.GetStamina();
+
+ pPlayer->m_Shared.SetStamina( flStamina - 15 );
+ }
+
+ BaseClass::PrimaryAttack();
+}
+
+Activity CWeapon30cal::GetDrawActivity( void )
+{
+ Activity actDraw;
+
+ if( m_iClip1 <= 0 )
+ actDraw = ACT_VM_DRAW_EMPTY;
+ else
+ actDraw = ACT_VM_DRAW;
+
+ return actDraw;
+}
+
+Activity CWeapon30cal::GetDeployActivity( void )
+{
+ Activity actDeploy;
+
+ switch ( m_iClip1 )
+ {
+ case 8:
+ actDeploy = ACT_VM_DEPLOY_8;
+ break;
+ case 7:
+ actDeploy = ACT_VM_DEPLOY_7;
+ break;
+ case 6:
+ actDeploy = ACT_VM_DEPLOY_6;
+ break;
+ case 5:
+ actDeploy = ACT_VM_DEPLOY_5;
+ break;
+ case 4:
+ actDeploy = ACT_VM_DEPLOY_4;
+ break;
+ case 3:
+ actDeploy = ACT_VM_DEPLOY_3;
+ break;
+ case 2:
+ actDeploy = ACT_VM_DEPLOY_2;
+ break;
+ case 1:
+ actDeploy = ACT_VM_DEPLOY_1;
+ break;
+ case 0:
+ actDeploy = ACT_VM_DEPLOY_EMPTY;
+ break;
+ default:
+ actDeploy = ACT_VM_DEPLOY;
+ break;
+ }
+
+ return actDeploy;
+}
+
+Activity CWeapon30cal::GetUndeployActivity( void )
+{
+ Activity actUndeploy;
+
+ switch ( m_iClip1 )
+ {
+ case 8:
+ actUndeploy = ACT_VM_UNDEPLOY_8;
+ break;
+ case 7:
+ actUndeploy = ACT_VM_UNDEPLOY_7;
+ break;
+ case 6:
+ actUndeploy = ACT_VM_UNDEPLOY_6;
+ break;
+ case 5:
+ actUndeploy = ACT_VM_UNDEPLOY_5;
+ break;
+ case 4:
+ actUndeploy = ACT_VM_UNDEPLOY_4;
+ break;
+ case 3:
+ actUndeploy = ACT_VM_UNDEPLOY_3;
+ break;
+ case 2:
+ actUndeploy = ACT_VM_UNDEPLOY_2;
+ break;
+ case 1:
+ actUndeploy = ACT_VM_UNDEPLOY_1;
+ break;
+ case 0:
+ actUndeploy = ACT_VM_UNDEPLOY_EMPTY;
+ break;
+ default:
+ actUndeploy = ACT_VM_UNDEPLOY;
+ break;
+ }
+
+ return actUndeploy;
+}
+
+Activity CWeapon30cal::GetIdleActivity( void )
+{
+ Activity actIdle;
+
+ if( IsDeployed() )
+ {
+ switch ( m_iClip1 )
+ {
+ case 8:
+ actIdle = ACT_VM_IDLE_DEPLOYED_8;
+ break;
+ case 7:
+ actIdle = ACT_VM_IDLE_DEPLOYED_7;
+ break;
+ case 6:
+ actIdle = ACT_VM_IDLE_DEPLOYED_6;
+ break;
+ case 5:
+ actIdle = ACT_VM_IDLE_DEPLOYED_5;
+ break;
+ case 4:
+ actIdle = ACT_VM_IDLE_DEPLOYED_4;
+ break;
+ case 3:
+ actIdle = ACT_VM_IDLE_DEPLOYED_3;
+ break;
+ case 2:
+ actIdle = ACT_VM_IDLE_DEPLOYED_2;
+ break;
+ case 1:
+ actIdle = ACT_VM_IDLE_DEPLOYED_1;
+ break;
+ case 0:
+ actIdle = ACT_VM_IDLE_DEPLOYED_EMPTY;
+ break;
+ default:
+ actIdle = ACT_VM_IDLE_DEPLOYED;
+ break;
+ }
+ }
+ else
+ {
+ switch ( m_iClip1 )
+ {
+ case 8:
+ actIdle = ACT_VM_IDLE_8;
+ break;
+ case 7:
+ actIdle = ACT_VM_IDLE_7;
+ break;
+ case 6:
+ actIdle = ACT_VM_IDLE_6;
+ break;
+ case 5:
+ actIdle = ACT_VM_IDLE_5;
+ break;
+ case 4:
+ actIdle = ACT_VM_IDLE_4;
+ break;
+ case 3:
+ actIdle = ACT_VM_IDLE_3;
+ break;
+ case 2:
+ actIdle = ACT_VM_IDLE_2;
+ break;
+ case 1:
+ actIdle = ACT_VM_IDLE_1;
+ break;
+ case 0:
+ actIdle = ACT_VM_IDLE_EMPTY;
+ break;
+ default:
+ actIdle = ACT_VM_IDLE;
+ break;
+ }
+ }
+
+ return actIdle;
+}
+
+Activity CWeapon30cal::GetPrimaryAttackActivity( void )
+{
+ Activity actPrim;
+
+ int maxhax = m_iClip1 + 2;
+
+ if( IsDeployed() )
+ {
+ switch ( maxhax )
+ {
+ case 8:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_8;
+ break;
+ case 7:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_7;
+ break;
+ case 6:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_6;
+ break;
+ case 5:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_5;
+ break;
+ case 4:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_4;
+ break;
+ case 3:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_3;
+ break;
+ case 2:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_2;
+ break;
+ case 1:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_1;
+ break;
+ case 0:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_EMPTY;
+ break;
+ default:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED;
+ break;
+ }
+ }
+ else
+ {
+ switch ( maxhax )
+ {
+ case 8:
+ actPrim = ACT_VM_PRIMARYATTACK_8;
+ break;
+ case 7:
+ actPrim = ACT_VM_PRIMARYATTACK_7;
+ break;
+ case 6:
+ actPrim = ACT_VM_PRIMARYATTACK_6;
+ break;
+ case 5:
+ actPrim = ACT_VM_PRIMARYATTACK_5;
+ break;
+ case 4:
+ actPrim = ACT_VM_PRIMARYATTACK_4;
+ break;
+ case 3:
+ actPrim = ACT_VM_PRIMARYATTACK_3;
+ break;
+ case 2:
+ actPrim = ACT_VM_PRIMARYATTACK_2;
+ break;
+ case 1:
+ actPrim = ACT_VM_PRIMARYATTACK_1;
+ break;
+ case 0:
+ actPrim = ACT_VM_PRIMARYATTACK_EMPTY;
+ break;
+ default:
+ actPrim = ACT_VM_PRIMARYATTACK;
+ break;
+ }
+ }
+
+ return actPrim;
+}
+
+float CWeapon30cal::GetRecoil( void )
+{
+ CDODPlayer *p = ToDODPlayer( GetPlayerOwner() );
+
+ if( p && p->m_Shared.IsInMGDeploy() )
+ {
+ return 0.0f;
+ }
+
+ return 20;
+}
diff --git a/game/shared/dod/weapon_amerknife.cpp b/game/shared/dod/weapon_amerknife.cpp
new file mode 100644
index 0000000..685487d
--- /dev/null
+++ b/game/shared/dod/weapon_amerknife.cpp
@@ -0,0 +1,77 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasemelee.h"
+#include "dod_shareddefs.h"
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponAmerKnife C_WeaponAmerKnife
+
+#endif
+
+
+class CWeaponAmerKnife : public CWeaponDODBaseMelee
+{
+public:
+ DECLARE_CLASS( CWeaponAmerKnife, CWeaponDODBaseMelee );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponAmerKnife() {}
+
+ virtual Activity GetMeleeActivity( void ) { return ACT_VM_PRIMARYATTACK; }
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_AMERKNIFE; }
+
+ virtual void PrimaryAttack()
+ {
+ MeleeAttack( 60, MELEE_DMG_FIST, 0.2f, 0.4f );
+ }
+
+private:
+ CWeaponAmerKnife( const CWeaponAmerKnife & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponAmerKnife, DT_WeaponAmerKnife )
+
+BEGIN_NETWORK_TABLE( CWeaponAmerKnife, DT_WeaponAmerKnife )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponAmerKnife )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_amerknife, CWeaponAmerKnife );
+PRECACHE_WEAPON_REGISTER( weapon_amerknife );
+
+acttable_t CWeaponAmerKnife::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_KNIFE, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_KNIFE, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_KNIFE, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_KNIFE, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_KNIFE, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_KNIFE, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_AIM_KNIFE, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_AIM_KNIFE, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_AIM_KNIFE, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_AIM_KNIFE, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_AIM_KNIFE, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_AIM_KNIFE, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_AIM_KNIFE, false },
+
+ { ACT_RANGE_ATTACK2, ACT_DOD_PRIMARYATTACK_KNIFE, false },
+ { ACT_DOD_SECONDARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_CROUCH_KNIFE, false },
+ { ACT_DOD_SECONDARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_KNIFE, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_KNIFE, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_KNIFE, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponAmerKnife );
diff --git a/game/shared/dod/weapon_bar.cpp b/game/shared/dod/weapon_bar.cpp
new file mode 100644
index 0000000..a8a3539
--- /dev/null
+++ b/game/shared/dod/weapon_bar.cpp
@@ -0,0 +1,84 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodfireselect.h"
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponBAR C_WeaponBAR
+
+#endif
+
+
+class CWeaponBAR : public CDODFireSelectWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponBAR, CDODFireSelectWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponBAR() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_BAR; }
+
+ // weapon id for stats purposes
+ virtual DODWeaponID GetStatsWeaponID( void )
+ {
+ if ( IsSemiAuto() )
+ return WEAPON_BAR_SEMIAUTO;
+ else
+ return WEAPON_BAR;
+ }
+
+ virtual float GetRecoil( void ) { return 5.0f; }
+
+private:
+ CWeaponBAR( const CWeaponBAR & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponBAR, DT_WeaponBAR )
+
+BEGIN_NETWORK_TABLE( CWeaponBAR, DT_WeaponBAR )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponBAR )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_bar, CWeaponBAR );
+PRECACHE_WEAPON_REGISTER( weapon_bar );
+
+acttable_t CWeaponBAR::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_BAR, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_BAR, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_BAR, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_BAR, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_BAR, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_BAR, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_BAR, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_BAR, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_BAR, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_BAR, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_BAR, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_BAR, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_BAR, false },
+
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_BAR, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_BAR, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_BAR, false },
+
+ { ACT_RELOAD, ACT_DOD_RELOAD_BAR, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_BAR, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_BAR, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_K98, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_K98, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponBAR ); \ No newline at end of file
diff --git a/game/shared/dod/weapon_bazooka.cpp b/game/shared/dod/weapon_bazooka.cpp
new file mode 100644
index 0000000..00240cc
--- /dev/null
+++ b/game/shared/dod/weapon_bazooka.cpp
@@ -0,0 +1,104 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbaserpg.h"
+
+#if defined( CLIENT_DLL )
+
+ #include "c_dod_player.h"
+ #define CWeaponBazooka C_WeaponBazooka
+
+#else
+
+ #include "rocket_bazooka.h"
+ #include "dod_player.h"
+
+#endif
+
+
+class CWeaponBazooka : public CDODBaseRocketWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponBazooka, CDODBaseRocketWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponBazooka() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_BAZOOKA; }
+
+ virtual void FireRocket( void );
+
+private:
+ CWeaponBazooka( const CWeaponBazooka & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponBazooka, DT_WeaponBazooka )
+
+BEGIN_NETWORK_TABLE( CWeaponBazooka, DT_WeaponBazooka )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponBazooka )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_bazooka, CWeaponBazooka );
+PRECACHE_WEAPON_REGISTER( weapon_bazooka );
+
+acttable_t CWeaponBazooka::m_acttable[] =
+{
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_BAZOOKA, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_BAZOOKA, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_BAZOOKA, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_BAZOOKA, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_BAZOOKA, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_BAZOOKA, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_BAZOOKA, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_BAZOOKA, false },
+
+ // Zoomed Aim
+ { ACT_DOD_IDLE_ZOOMED, ACT_DOD_STAND_ZOOM_BAZOOKA, false },
+ { ACT_DOD_CROUCH_ZOOMED, ACT_DOD_CROUCH_ZOOM_BAZOOKA, false },
+ { ACT_DOD_CROUCHWALK_ZOOMED, ACT_DOD_CROUCHWALK_ZOOM_BAZOOKA, false },
+ { ACT_DOD_WALK_ZOOMED, ACT_DOD_WALK_ZOOM_BAZOOKA, false },
+ { ACT_DOD_PRONE_ZOOMED, ACT_DOD_PRONE_ZOOM_BAZOOKA, false },
+ { ACT_DOD_PRONE_FORWARD_ZOOMED, ACT_DOD_PRONE_ZOOM_FORWARD_BAZOOKA, false },
+
+ // Attack ( must be zoomed )
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_BAZOOKA, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_BAZOOKA, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_BAZOOKA, false },
+
+ // Reload ( zoomed or not, prone or not )
+ { ACT_RELOAD, ACT_DOD_RELOAD_BAZOOKA, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_BAZOOKA, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_BAZOOKA, false },
+ { ACT_DOD_RELOAD_DEPLOYED, ACT_DOD_ZOOMLOAD_BAZOOKA, false },
+ { ACT_DOD_RELOAD_PRONE_DEPLOYED, ACT_DOD_ZOOMLOAD_PRONE_BAZOOKA, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_BAZOOKA, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_BAZOOKA, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponBazooka );
+
+void CWeaponBazooka::FireRocket( void )
+{
+#ifndef CLIENT_DLL
+
+ CBasePlayer *pPlayer = GetPlayerOwner();
+
+#ifdef DBGFLAG_ASSERT
+ CBazookaRocket *pRocket =
+#endif //DEBUG
+ CBazookaRocket::Create( pPlayer->Weapon_ShootPosition(), pPlayer->EyeAngles(), pPlayer );
+
+ Assert( pRocket );
+
+#endif
+}
diff --git a/game/shared/dod/weapon_c96.cpp b/game/shared/dod/weapon_c96.cpp
new file mode 100644
index 0000000..c9a0e62
--- /dev/null
+++ b/game/shared/dod/weapon_c96.cpp
@@ -0,0 +1,131 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodfullauto.h"
+
+
+#if defined( CLIENT_DLL )
+
+#define CWeaponC96 C_WeaponC96
+
+#endif
+
+
+class CWeaponC96 : public CDODFullAutoWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponC96, CDODFullAutoWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponC96() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_C96; }
+
+ virtual Activity GetIdleActivity( void );
+ virtual Activity GetPrimaryAttackActivity( void );
+ virtual Activity GetDrawActivity( void );
+ virtual Activity GetReloadActivity( void );
+
+ virtual float GetRecoil( void ) { return 3.0f; }
+
+private:
+ CWeaponC96( const CWeaponC96 & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponC96, DT_WeaponC96 )
+
+BEGIN_NETWORK_TABLE( CWeaponC96, DT_WeaponC96 )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponC96 )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_c96, CWeaponC96 );
+PRECACHE_WEAPON_REGISTER( weapon_c96 );
+
+acttable_t CWeaponC96::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_C96, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_C96, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_C96, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_C96, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_C96, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_C96, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_C96, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_C96, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_C96, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_C96, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_C96, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_C96, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_C96, false },
+
+ // Attack ( prone? )
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_C96, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_C96, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_C96,false },
+
+ // Reload ( prone? )
+ { ACT_RELOAD, ACT_DOD_RELOAD_C96, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_C96, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_C96, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_MP44, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_MP44, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponC96 );
+
+Activity CWeaponC96::GetIdleActivity( void )
+{
+ Activity actIdle;
+
+ if( m_iClip1 <= 0 )
+ actIdle = ACT_VM_IDLE_EMPTY;
+ else
+ actIdle = ACT_VM_IDLE;
+
+ return actIdle;
+}
+
+Activity CWeaponC96::GetPrimaryAttackActivity( void )
+{
+ Activity actPrim;
+
+ if( m_iClip1 <= 0 )
+ actPrim = ACT_VM_PRIMARYATTACK_EMPTY;
+ else
+ actPrim = ACT_VM_PRIMARYATTACK;
+
+ return actPrim;
+}
+
+Activity CWeaponC96::GetDrawActivity( void )
+{
+ Activity actDraw;
+
+ if( m_iClip1 <= 0 )
+ actDraw = ACT_VM_DRAW_EMPTY;
+ else
+ actDraw = ACT_VM_DRAW;
+
+ return actDraw;
+}
+
+Activity CWeaponC96::GetReloadActivity( void )
+{
+ Activity actReload;
+
+ if( m_iClip1 <= 0 )
+ actReload = ACT_VM_RELOAD_EMPTY;
+ else
+ actReload = ACT_VM_RELOAD;
+
+ return actReload;
+} \ No newline at end of file
diff --git a/game/shared/dod/weapon_colt.cpp b/game/shared/dod/weapon_colt.cpp
new file mode 100644
index 0000000..3715087
--- /dev/null
+++ b/game/shared/dod/weapon_colt.cpp
@@ -0,0 +1,128 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodsemiauto.h"
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponColt C_WeaponColt
+
+#endif
+
+
+class CWeaponColt : public CDODSemiAutoWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponColt, CDODSemiAutoWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponColt() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_COLT; }
+
+ virtual Activity GetIdleActivity( void );
+ virtual Activity GetPrimaryAttackActivity( void );
+ virtual Activity GetDrawActivity( void );
+ virtual Activity GetReloadActivity( void );
+
+ virtual float GetRecoil( void ) { return 1.4f; }
+
+private:
+ CWeaponColt( const CWeaponColt & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponColt, DT_WeaponColt )
+
+BEGIN_NETWORK_TABLE( CWeaponColt, DT_WeaponColt )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponColt )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_colt, CWeaponColt );
+PRECACHE_WEAPON_REGISTER( weapon_colt );
+
+acttable_t CWeaponColt::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_PISTOL, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_PISTOL, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_PISTOL, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_PISTOL, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_PISTOL, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_PISTOL, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_PISTOL, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_PISTOL, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_PISTOL, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_PISTOL, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_PISTOL, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_PISTOL, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_PISTOL, false },
+
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_PISTOL, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_PISTOL, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_PISTOL, false },
+
+ { ACT_RELOAD, ACT_DOD_RELOAD_PISTOL, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_PISTOL, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_PISTOL, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_PISTOL, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_PISTOL, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponColt );
+
+Activity CWeaponColt::GetIdleActivity( void )
+{
+ Activity actIdle;
+
+ if( m_iClip1 <= 0 )
+ actIdle = ACT_VM_IDLE_EMPTY;
+ else
+ actIdle = ACT_VM_IDLE;
+
+ return actIdle;
+}
+
+Activity CWeaponColt::GetPrimaryAttackActivity( void )
+{
+ Activity actPrim;
+
+ if( m_iClip1 <= 0 )
+ actPrim = ACT_VM_PRIMARYATTACK_EMPTY;
+ else
+ actPrim = ACT_VM_PRIMARYATTACK;
+
+ return actPrim;
+}
+
+Activity CWeaponColt::GetDrawActivity( void )
+{
+ Activity actDraw;
+
+ if( m_iClip1 <= 0 )
+ actDraw = ACT_VM_DRAW_EMPTY;
+ else
+ actDraw = ACT_VM_DRAW;
+
+ return actDraw;
+}
+
+Activity CWeaponColt::GetReloadActivity( void )
+{
+ Activity actReload;
+
+ if( m_iClip1 <= 0 )
+ actReload = ACT_VM_RELOAD_EMPTY;
+ else
+ actReload = ACT_VM_RELOAD;
+
+ return actReload;
+} \ No newline at end of file
diff --git a/game/shared/dod/weapon_dodbase.cpp b/game/shared/dod/weapon_dodbase.cpp
new file mode 100644
index 0000000..3c1fc98
--- /dev/null
+++ b/game/shared/dod/weapon_dodbase.cpp
@@ -0,0 +1,1416 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "in_buttons.h"
+#include "takedamageinfo.h"
+#include "weapon_dodbase.h"
+#include "ammodef.h"
+#include "dod_gamerules.h"
+
+#ifdef CLIENT_DLL
+extern IVModelInfoClient* modelinfo;
+#else
+extern IVModelInfo* modelinfo;
+#include "ilagcompensationmanager.h"
+#endif
+
+
+#if defined( CLIENT_DLL )
+
+ #include "vgui/ISurface.h"
+ #include "vgui_controls/Controls.h"
+ #include "c_dod_player.h"
+ #include "hud_crosshair.h"
+ #include "SoundEmitterSystem/isoundemittersystembase.h"
+
+#else
+
+ #include "dod_player.h"
+
+#endif
+
+#include "effect_dispatch_data.h"
+
+
+// ----------------------------------------------------------------------------- //
+// Global functions.
+// ----------------------------------------------------------------------------- //
+
+bool IsAmmoType( int iAmmoType, const char *pAmmoName )
+{
+ return GetAmmoDef()->Index( pAmmoName ) == iAmmoType;
+}
+
+//--------------------------------------------------------------------------------------------------------
+//
+// Given a weapon ID, return its alias
+//
+const char *WeaponIDToAlias( int id )
+{
+ if ( (id >= WEAPON_MAX) || (id < 0) )
+ return NULL;
+
+ return s_WeaponAliasInfo[id];
+}
+
+// ----------------------------------------------------------------------------- //
+// CWeaponDODBase tables.
+// ----------------------------------------------------------------------------- //
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponDODBase, DT_WeaponDODBase )
+
+BEGIN_NETWORK_TABLE( CWeaponDODBase, DT_WeaponDODBase )
+#ifdef CLIENT_DLL
+ RecvPropInt( RECVINFO(m_iReloadModelIndex) ),
+ RecvPropVector( RECVINFO( m_vInitialDropVelocity ) ),
+ RecvPropTime( RECVINFO( m_flSmackTime ) )
+#else
+ SendPropVector( SENDINFO( m_vInitialDropVelocity ),
+ 20, // nbits
+ 0, // flags
+ -3000, // low value
+ 3000 // high value
+ ),
+ SendPropModelIndex( SENDINFO(m_iReloadModelIndex) ),
+ SendPropTime( SENDINFO( m_flSmackTime ) )
+#endif
+END_NETWORK_TABLE()
+
+LINK_ENTITY_TO_CLASS( weapon_dod_base, CWeaponDODBase );
+
+
+#ifdef GAME_DLL
+
+ BEGIN_DATADESC( CWeaponDODBase )
+
+ DEFINE_FUNCTION( FallThink ),
+ DEFINE_FUNCTION( Die ),
+
+ DEFINE_FUNCTION( Smack )
+
+ END_DATADESC()
+
+#else
+ BEGIN_PREDICTION_DATA( CWeaponDODBase )
+ DEFINE_PRED_FIELD( m_flSmackTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), // for rifle melee attacks
+ DEFINE_FIELD( m_bInAttack, FIELD_BOOLEAN )
+ END_PREDICTION_DATA()
+#endif
+
+Vector head_hull_mins( -16, -16, -18 );
+Vector head_hull_maxs( 16, 16, 18 );
+
+void FindHullIntersection( const Vector &vecSrc, trace_t &tr, const Vector &mins, const Vector &maxs, CBaseEntity *pEntity )
+{
+ int i, j, k;
+ float distance;
+ Vector minmaxs[2] = {mins, maxs};
+ trace_t tmpTrace;
+ Vector vecHullEnd = tr.endpos;
+ Vector vecEnd;
+
+ CTraceFilterSimple filter( pEntity, COLLISION_GROUP_NONE );
+
+ distance = 1e6f;
+
+ vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2);
+ UTIL_TraceLine( vecSrc, vecHullEnd, MASK_SOLID, &filter, &tmpTrace );
+ if ( tmpTrace.fraction < 1.0 )
+ {
+ tr = tmpTrace;
+ return;
+ }
+
+ for ( i = 0; i < 2; i++ )
+ {
+ for ( j = 0; j < 2; j++ )
+ {
+ for ( k = 0; k < 2; k++ )
+ {
+ vecEnd.x = vecHullEnd.x + minmaxs[i][0];
+ vecEnd.y = vecHullEnd.y + minmaxs[j][1];
+ vecEnd.z = vecHullEnd.z + minmaxs[k][2];
+
+ UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID, &filter, &tmpTrace );
+ if ( tmpTrace.fraction < 1.0 )
+ {
+ float thisDistance = (tmpTrace.endpos - vecSrc).Length();
+ if ( thisDistance < distance )
+ {
+ tr = tmpTrace;
+ distance = thisDistance;
+ }
+ }
+ }
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------- //
+// CWeaponDODBase implementation.
+// ----------------------------------------------------------------------------- //
+CWeaponDODBase::CWeaponDODBase()
+{
+ SetPredictionEligible( true );
+ m_bInAttack = false;
+ m_iAltFireHint = 0;
+ AddSolidFlags( FSOLID_TRIGGER ); // Nothing collides with these but it gets touches.
+
+ m_flNextPrimaryAttack = 0;
+}
+
+
+bool CWeaponDODBase::IsPredicted() const
+{
+ return true;
+}
+
+bool CWeaponDODBase::PlayEmptySound()
+{
+ CPASAttenuationFilter filter( this );
+ filter.UsePredictionRules();
+ EmitSound( filter, entindex(), "Default.ClipEmpty_Rifle" );
+
+ return false;
+}
+
+
+CBasePlayer* CWeaponDODBase::GetPlayerOwner() const
+{
+ return dynamic_cast< CBasePlayer* >( GetOwner() );
+}
+
+CDODPlayer* CWeaponDODBase::GetDODPlayerOwner() const
+{
+ return dynamic_cast< CDODPlayer* >( GetOwner() );
+}
+
+bool CWeaponDODBase::SendWeaponAnim( int iActivity )
+{
+ return BaseClass::SendWeaponAnim( iActivity );
+}
+
+bool CWeaponDODBase::CanAttack( void )
+{
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+ if ( pPlayer )
+ {
+ return pPlayer->CanAttack();
+ }
+
+ return false;
+}
+
+bool CWeaponDODBase::ShouldAutoReload( void )
+{
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+ if ( pPlayer )
+ {
+ return pPlayer->ShouldAutoReload();
+ }
+
+ return false;
+}
+
+void CWeaponDODBase::ItemPostFrame()
+{
+ if ( m_flSmackTime > 0 && gpGlobals->curtime > m_flSmackTime )
+ {
+ Smack();
+ m_flSmackTime = -1;
+ }
+
+ CBasePlayer *pPlayer = GetPlayerOwner();
+
+ if ( !pPlayer )
+ return;
+
+#ifdef _DEBUG
+ CDODGameRules *mp = DODGameRules();
+#endif
+
+ assert( mp );
+
+ if ((m_bInReload) && (pPlayer->m_flNextAttack <= gpGlobals->curtime))
+ {
+ // complete the reload.
+ int j = MIN( GetMaxClip1() - m_iClip1, pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) );
+
+ // Add them to the clip
+ m_iClip1 += j;
+ pPlayer->RemoveAmmo( j, m_iPrimaryAmmoType );
+
+ m_bInReload = false;
+
+ FinishReload();
+ }
+
+ if ((pPlayer->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime))
+ {
+ if ( m_iClip2 != -1 && !pPlayer->GetAmmoCount( GetSecondaryAmmoType() ) )
+ {
+ m_bFireOnEmpty = TRUE;
+ }
+
+ SecondaryAttack();
+
+ pPlayer->m_nButtons &= ~IN_ATTACK2;
+ }
+ else if ((pPlayer->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime ) && !m_bInAttack )
+ {
+ if ( (m_iClip1 == 0/* && pszAmmo1()*/) || (GetMaxClip1() == -1 && !pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) ) )
+ {
+ m_bFireOnEmpty = TRUE;
+ }
+
+ if( CanAttack() )
+ PrimaryAttack();
+ }
+ else if ( pPlayer->m_nButtons & IN_RELOAD && GetMaxClip1() != WEAPON_NOCLIP && !m_bInReload && m_flNextPrimaryAttack < gpGlobals->curtime)
+ {
+ // reload when reload is pressed, or if no buttons are down and weapon is empty.
+ Reload();
+ }
+ else if ( !(pPlayer->m_nButtons & (IN_ATTACK|IN_ATTACK2) ) )
+ {
+ // no fire buttons down
+
+ m_bFireOnEmpty = false;
+
+ m_bInAttack = false; //reset semi-auto
+
+ if ( !IsUseable() && m_flNextPrimaryAttack < gpGlobals->curtime )
+ {
+ // Intentionally blank -- used to switch weapons here
+ }
+ else if( ShouldAutoReload() )
+ {
+ // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
+ if ( m_iClip1 == 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime )
+ {
+ Reload();
+ return;
+ }
+ }
+
+ WeaponIdle( );
+ return;
+ }
+}
+
+void CWeaponDODBase::WeaponIdle()
+{
+ if (m_flTimeWeaponIdle > gpGlobals->curtime)
+ return;
+
+ SendWeaponAnim( GetIdleActivity() );
+
+ m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
+}
+
+Activity CWeaponDODBase::GetIdleActivity( void )
+{
+ return ACT_VM_IDLE;
+}
+
+const CDODWeaponInfo &CWeaponDODBase::GetDODWpnData() const
+{
+ const FileWeaponInfo_t *pWeaponInfo = &GetWpnData();
+ const CDODWeaponInfo *pDODInfo;
+
+ #ifdef _DEBUG
+ pDODInfo = dynamic_cast< const CDODWeaponInfo* >( pWeaponInfo );
+ Assert( pDODInfo );
+ #else
+ pDODInfo = static_cast< const CDODWeaponInfo* >( pWeaponInfo );
+ #endif
+
+ return *pDODInfo;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *CWeaponDODBase::GetViewModel( int /*viewmodelindex = 0 -- this is ignored in the base class here*/ ) const
+{
+ if ( GetPlayerOwner() == NULL )
+ {
+ return BaseClass::GetViewModel();
+ }
+
+ return GetWpnData().szViewModel;
+}
+
+void CWeaponDODBase::Precache( void )
+{
+ // precache base first, it loads weapon scripts
+ BaseClass::Precache();
+
+ PrecacheScriptSound( "Default.ClipEmpty_Rifle" );
+
+ PrecacheParticleSystem( "muzzle_pistols" );
+ PrecacheParticleSystem( "muzzle_fullyautomatic" );
+ PrecacheParticleSystem( "muzzle_rifles" );
+ PrecacheParticleSystem( "muzzle_rockets" );
+ PrecacheParticleSystem( "muzzle_mg42" );
+
+ PrecacheParticleSystem( "view_muzzle_pistols" );
+ PrecacheParticleSystem( "view_muzzle_fullyautomatic" );
+ PrecacheParticleSystem( "view_muzzle_rifles" );
+ PrecacheParticleSystem( "view_muzzle_rockets" );
+ PrecacheParticleSystem( "view_muzzle_mg42" );
+
+ const CDODWeaponInfo &info = GetDODWpnData();
+
+ int iWpnNameLen = Q_strlen(info.m_szReloadModel);
+
+#ifdef DEBUG
+ // Make sure that if we declare an alt weapon, that we have criteria to show it
+ // and vice-versa
+ //Assert( ((info.m_iAltWpnCriteria & (ALTWPN_CRITERIA_RELOADING | ALTWPN_CRITERIA_FIRING)) > 0 ) ==
+ // (iWpnNameLen > 0) );
+#endif
+
+ if( iWpnNameLen > 0 )
+ m_iReloadModelIndex = CBaseEntity::PrecacheModel( info.m_szReloadModel );
+}
+
+bool CWeaponDODBase::DefaultDeploy( char *szViewModel, char *szWeaponModel, int iActivity, char *szAnimExt )
+{
+ CBasePlayer *pOwner = GetPlayerOwner();
+ if ( !pOwner )
+ {
+ return false;
+ }
+
+ pOwner->SetAnimationExtension( szAnimExt );
+
+ SetViewModel();
+ SendWeaponAnim( iActivity );
+
+ pOwner->SetNextAttack( gpGlobals->curtime + SequenceDuration() );
+ m_flNextPrimaryAttack = MAX( m_flNextPrimaryAttack, gpGlobals->curtime );
+ m_flNextSecondaryAttack = gpGlobals->curtime;
+
+ SetWeaponVisible( true );
+ SetWeaponModelIndex( szWeaponModel );
+
+ CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
+
+ Assert( vm );
+
+ if( vm )
+ {
+ //set sleeves to proper team
+ switch( pOwner->GetTeamNumber() )
+ {
+ case TEAM_ALLIES:
+ vm->m_nSkin = SLEEVE_ALLIES;
+ break;
+ case TEAM_AXIS:
+ vm->m_nSkin = SLEEVE_AXIS;
+ break;
+ default:
+ Assert( !"TEAM_UNASSIGNED or spectator getting a view model assigned" );
+ break;
+ }
+ }
+
+ return true;
+}
+
+void CWeaponDODBase::SetWeaponModelIndex( const char *pName )
+{
+ m_iWorldModelIndex = modelinfo->GetModelIndex( pName );
+}
+
+bool CWeaponDODBase::CanBeSelected( void )
+{
+ if ( !VisibleInWeaponSelection() )
+ return false;
+
+ return true;
+}
+
+bool CWeaponDODBase::CanDeploy( void )
+{
+ return BaseClass::CanDeploy();
+}
+
+bool CWeaponDODBase::CanHolster( void )
+{
+ return BaseClass::CanHolster();
+}
+
+void CWeaponDODBase::Drop( const Vector &vecVelocity )
+{
+#ifndef CLIENT_DLL
+ if ( m_iAltFireHint )
+ {
+ CDODPlayer *pPlayer = GetDODPlayerOwner();
+ if ( pPlayer )
+ {
+ pPlayer->StopHintTimer( m_iAltFireHint );
+ }
+ }
+#endif
+
+ // cancel any reload in progress
+ m_bInReload = false;
+
+ m_flSmackTime = -1;
+
+ m_vInitialDropVelocity = vecVelocity;
+
+ BaseClass::Drop( m_vInitialDropVelocity );
+}
+
+bool CWeaponDODBase::Holster( CBaseCombatWeapon *pSwitchingTo )
+{
+#ifndef CLIENT_DLL
+ CDODPlayer *pPlayer = GetDODPlayerOwner();
+
+ if ( pPlayer )
+ {
+ pPlayer->SetFOV( pPlayer, 0 ); // reset the default FOV.
+
+ if ( m_iAltFireHint )
+ {
+ pPlayer->StopHintTimer( m_iAltFireHint );
+ }
+ }
+#endif
+
+ m_bInReload = false;
+
+ m_flSmackTime = -1;
+
+ return BaseClass::Holster( pSwitchingTo );
+}
+
+bool CWeaponDODBase::Deploy()
+{
+#ifndef CLIENT_DLL
+ CDODPlayer *pPlayer = GetDODPlayerOwner();
+
+ if ( pPlayer )
+ {
+ pPlayer->SetFOV( pPlayer, 0 );
+
+ if ( m_iAltFireHint )
+ {
+ pPlayer->StartHintTimer( m_iAltFireHint );
+ }
+ }
+#endif
+
+ return BaseClass::Deploy();
+}
+
+#ifdef CLIENT_DLL
+
+ void CWeaponDODBase::PostDataUpdate( DataUpdateType_t updateType )
+ {
+ // We need to do this before the C_BaseAnimating code starts to drive
+ // clientside animation sequences on this model, which will be using bad sequences for the world model.
+ int iDesiredModelIndex = 0;
+ C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();
+ if ( localplayer && localplayer == GetOwner() && !C_BasePlayer::ShouldDrawLocalPlayer() ) // FIXME: use localplayer->ShouldDrawThisPlayer() instead.
+ {
+ iDesiredModelIndex = m_iViewModelIndex;
+ }
+ else
+ {
+ iDesiredModelIndex = GetWorldModelIndex();
+
+ // Our world models never animate
+ SetSequence( 0 );
+ }
+
+ if ( GetModelIndex() != iDesiredModelIndex )
+ {
+ SetModelIndex( iDesiredModelIndex );
+ }
+
+ BaseClass::PostDataUpdate( updateType );
+ }
+
+ void CWeaponDODBase::OnDataChanged( DataUpdateType_t type )
+ {
+ if ( m_iState == WEAPON_NOT_CARRIED && m_iOldState != WEAPON_NOT_CARRIED )
+ {
+ // we are being notified of the weapon being dropped
+ // add an interpolation history so the movement is smoother
+
+ // Now stick our initial velocity into the interpolation history
+ CInterpolatedVar< Vector > &interpolator = GetOriginInterpolator();
+
+ interpolator.ClearHistory();
+ float changeTime = GetLastChangeTime( LATCH_SIMULATION_VAR );
+
+ // Add a sample 1 second back.
+ Vector vCurOrigin = GetLocalOrigin() - m_vInitialDropVelocity;
+ interpolator.AddToHead( changeTime - 1.0, &vCurOrigin, false );
+
+ // Add the current sample.
+ vCurOrigin = GetLocalOrigin();
+ interpolator.AddToHead( changeTime, &vCurOrigin, false );
+
+ Vector estVel;
+ EstimateAbsVelocity( estVel );
+
+ /*Msg( "estimated velocity ( %.1f %.1f %.1f ) initial velocity ( %.1f %.1f %.1f )\n",
+ estVel.x,
+ estVel.y,
+ estVel.z,
+ m_vInitialDropVelocity.m_Value.x,
+ m_vInitialDropVelocity.m_Value.y,
+ m_vInitialDropVelocity.m_Value.z );*/
+
+ OnWeaponDropped();
+ }
+
+ BaseClass::OnDataChanged( type );
+
+ if ( GetPredictable() && !ShouldPredict() )
+ ShutdownPredictable();
+ }
+
+ int CWeaponDODBase::GetWorldModelIndex( void )
+ {
+ if( m_bUseAltWeaponModel && GetOwner() != NULL )
+ return m_iReloadModelIndex;
+ else
+ return m_iWorldModelIndex;
+ }
+
+ bool CWeaponDODBase::ShouldPredict()
+ {
+ if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() )
+ return true;
+
+ return BaseClass::ShouldPredict();
+ }
+
+ void CWeaponDODBase::ProcessMuzzleFlashEvent()
+ {
+ CDODPlayer *pPlayer = GetDODPlayerOwner();
+ if ( pPlayer )
+ pPlayer->ProcessMuzzleFlashEvent();
+
+ BaseClass::ProcessMuzzleFlashEvent();
+ }
+#else
+
+
+ //-----------------------------------------------------------------------------
+ // Purpose: Get the accuracy derived from weapon and player, and return it
+ //-----------------------------------------------------------------------------
+ const Vector& CWeaponDODBase::GetBulletSpread()
+ {
+ static Vector cone = VECTOR_CONE_8DEGREES;
+ return cone;
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ void CWeaponDODBase::ItemBusyFrame()
+ {
+ if( ShouldAutoReload() && !m_bInReload )
+ {
+ // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
+ if ( m_iClip1 == 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime )
+ {
+ Reload();
+ }
+ }
+
+ BaseClass::ItemBusyFrame();
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose: Match the anim speed to the weapon speed while crouching
+ //-----------------------------------------------------------------------------
+ float CWeaponDODBase::GetDefaultAnimSpeed()
+ {
+ return 1.0;
+ }
+
+ bool CWeaponDODBase::ShouldRemoveOnRoundRestart()
+ {
+ if ( GetPlayerOwner() )
+ return false;
+ else
+ return true;
+ }
+
+
+ //=========================================================
+ // Materialize - make a CWeaponDODBase visible and tangible
+ //=========================================================
+ void CWeaponDODBase::Materialize()
+ {
+ if ( IsEffectActive( EF_NODRAW ) )
+ {
+ RemoveEffects( EF_NODRAW );
+ DoMuzzleFlash();
+ }
+
+ AddSolidFlags( FSOLID_TRIGGER );
+
+ SetThink (&CWeaponDODBase::SUB_Remove);
+ SetNextThink( gpGlobals->curtime + 1 );
+ }
+
+ //=========================================================
+ // AttemptToMaterialize - the item is trying to rematerialize,
+ // should it do so now or wait longer?
+ //=========================================================
+ void CWeaponDODBase::AttemptToMaterialize()
+ {
+ float time = g_pGameRules->FlWeaponTryRespawn( this );
+
+ if ( time == 0 )
+ {
+ Materialize();
+ return;
+ }
+
+ SetNextThink( gpGlobals->curtime + time );
+ }
+
+ //=========================================================
+ // CheckRespawn - a player is taking this weapon, should
+ // it respawn?
+ //=========================================================
+ void CWeaponDODBase::CheckRespawn()
+ {
+ //GOOSEMAN : Do not respawn weapons!
+ return;
+ }
+
+
+ //=========================================================
+ // Respawn- this item is already in the world, but it is
+ // invisible and intangible. Make it visible and tangible.
+ //=========================================================
+ CBaseEntity* CWeaponDODBase::Respawn()
+ {
+ // make a copy of this weapon that is invisible and inaccessible to players (no touch function). The weapon spawn/respawn code
+ // will decide when to make the weapon visible and touchable.
+ CBaseEntity *pNewWeapon = CBaseEntity::Create( GetClassname(), g_pGameRules->VecWeaponRespawnSpot( this ), GetAbsAngles(), GetOwner() );
+
+ if ( pNewWeapon )
+ {
+ pNewWeapon->AddEffects( EF_NODRAW );// invisible for now
+ pNewWeapon->SetTouch( NULL );// no touch
+ pNewWeapon->SetThink( &CWeaponDODBase::AttemptToMaterialize );
+
+ UTIL_DropToFloor( this, MASK_SOLID );
+
+ // not a typo! We want to know when the weapon the player just picked up should respawn! This new entity we created is the replacement,
+ // but when it should respawn is based on conditions belonging to the weapon that was taken.
+ pNewWeapon->SetNextThink( gpGlobals->curtime + g_pGameRules->FlWeaponRespawnTime( this ) );
+ }
+ else
+ {
+ Msg( "Respawn failed to create %s!\n", GetClassname() );
+ }
+
+ return pNewWeapon;
+ }
+
+ bool CWeaponDODBase::Reload()
+ {
+ return BaseClass::Reload();
+ }
+
+ void CWeaponDODBase::Spawn()
+ {
+ BaseClass::Spawn();
+
+ // Set this here to allow players to shoot dropped weapons
+ SetCollisionGroup( COLLISION_GROUP_WEAPON );
+
+ SetExtraAmmoCount(0); //Start with no additional ammo
+
+ CollisionProp()->UseTriggerBounds( true, 10.0f );
+ }
+
+ void CWeaponDODBase::SetDieThink( bool bDie )
+ {
+ if( bDie )
+ SetContextThink( &CWeaponDODBase::Die, gpGlobals->curtime + 45.0f, "DieContext" );
+ else
+ SetContextThink( NULL, gpGlobals->curtime, "DieContext" );
+ }
+
+ void CWeaponDODBase::Die( void )
+ {
+ UTIL_Remove( this );
+ }
+
+#endif
+
+void CWeaponDODBase::OnPickedUp( CBaseCombatCharacter *pNewOwner )
+{
+ BaseClass::OnPickedUp( pNewOwner );
+
+#if !defined( CLIENT_DLL )
+ SetDieThink( false );
+#endif
+}
+
+bool CWeaponDODBase::DefaultReload( int iClipSize1, int iClipSize2, int iActivity )
+{
+ CBaseCombatCharacter *pOwner = GetOwner();
+ if (!pOwner)
+ return false;
+
+ // If I don't have any spare ammo, I can't reload
+ if ( pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
+ return false;
+
+ bool bReload = false;
+
+ // If you don't have clips, then don't try to reload them.
+ if ( UsesClipsForAmmo1() )
+ {
+ // need to reload primary clip?
+ int primary = min(iClipSize1 - m_iClip1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
+ if ( primary != 0 )
+ {
+ bReload = true;
+ }
+ }
+
+ if ( UsesClipsForAmmo2() )
+ {
+ // need to reload secondary clip?
+ int secondary = min(iClipSize2 - m_iClip2, pOwner->GetAmmoCount(m_iSecondaryAmmoType));
+ if ( secondary != 0 )
+ {
+ bReload = true;
+ }
+ }
+
+ if ( !bReload )
+ return false;
+
+ CDODPlayer *pPlayer = GetDODPlayerOwner();
+ if ( pPlayer )
+ {
+#ifdef CLIENT_DLL
+ PlayWorldReloadSound( pPlayer );
+#else
+ pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD );
+#endif
+ }
+
+ SendWeaponAnim( iActivity );
+
+ // Play the player's reload animation
+ if ( pOwner->IsPlayer() )
+ {
+ ( ( CBasePlayer * )pOwner)->SetAnimation( PLAYER_RELOAD );
+ }
+
+ float flSequenceEndTime = gpGlobals->curtime + SequenceDuration();
+ pOwner->SetNextAttack( flSequenceEndTime );
+ m_flNextPrimaryAttack = m_flNextSecondaryAttack = flSequenceEndTime;
+
+ m_bInReload = true;
+
+ return true;
+}
+
+#ifdef CLIENT_DLL
+ void CWeaponDODBase::PlayWorldReloadSound( CDODPlayer *pPlayer )
+ {
+ Assert( pPlayer );
+
+ const char *shootsound = GetShootSound( RELOAD );
+ if ( !shootsound || !shootsound[0] )
+ return;
+
+ CSoundParameters params;
+
+ if ( !GetParametersForSound( shootsound, params, NULL ) )
+ return;
+
+ // Play weapon sound from the owner
+ CPASAttenuationFilter filter( pPlayer, params.soundlevel );
+ filter.RemoveRecipient( pPlayer ); // no local player, that is done in the model
+
+ EmitSound( filter, pPlayer->entindex(), shootsound, NULL, 0.0 );
+ }
+#endif
+
+bool CWeaponDODBase::IsUseable()
+{
+ CBasePlayer *pPlayer = GetPlayerOwner();
+
+ if ( Clip1() <= 0 )
+ {
+ if ( pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0 && GetMaxClip1() != -1 )
+ {
+ // clip is empty (or nonexistant) and the player has no more ammo of this type.
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#ifndef CLIENT_DLL
+ConVar dod_meleeattackforcescale( "dod_meleeattackforcescale", "8.0", FCVAR_CHEAT | FCVAR_GAMEDLL );
+#endif
+
+void CWeaponDODBase::RifleButt( void )
+{
+ //MeleeAttack( 60, MELEE_DMG_BUTTSTOCK | MELEE_DMG_SECONDARYATTACK, 0.2f, 0.9f );
+}
+
+void CWeaponDODBase::Bayonet( void )
+{
+ //MeleeAttack( 60, MELEE_DMG_BAYONET | MELEE_DMG_SECONDARYATTACK, 0.2f, 0.9f );
+}
+
+void CWeaponDODBase::Punch( void )
+{
+ MeleeAttack( 60, MELEE_DMG_FIST | MELEE_DMG_SECONDARYATTACK, 0.2f, 0.4f );
+}
+
+//--------------------------------------------
+// iDamageAmount - how much damage to give
+// iDamageType - DMG_ bits
+// flDmgDelay - delay between attack and the giving of damage, usually timed to animation
+// flAttackDelay - time until we can next attack
+//--------------------------------------------
+CBaseEntity *CWeaponDODBase::MeleeAttack( int iDamageAmount, int iDamageType, float flDmgDelay, float flAttackDelay )
+{
+ if ( !CanAttack() )
+ return NULL;
+
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+#if !defined (CLIENT_DLL)
+ // Move other players back to history positions based on local player's lag
+ lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() );
+#endif
+
+ Vector vForward, vRight, vUp;
+ AngleVectors( pPlayer->EyeAngles(), &vForward, &vRight, &vUp );
+ Vector vecSrc = pPlayer->Weapon_ShootPosition();
+ Vector vecEnd = vecSrc + vForward * 48;
+
+ CTraceFilterSimple filter( pPlayer, COLLISION_GROUP_NONE );
+
+ int iTraceMask = MASK_SOLID | CONTENTS_HITBOX | CONTENTS_DEBRIS;
+
+ trace_t tr;
+ UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &filter, &tr );
+
+ const float rayExtension = 40.0f;
+ UTIL_ClipTraceToPlayers( vecSrc, vecEnd + vForward * rayExtension, iTraceMask, &filter, &tr );
+
+ // If the exact forward trace did not hit, try a larger swept box
+ if ( tr.fraction >= 1.0 )
+ {
+ Vector head_hull_mins( -16, -16, -18 );
+ Vector head_hull_maxs( 16, 16, 18 );
+
+ UTIL_TraceHull( vecSrc, vecEnd, head_hull_mins, head_hull_maxs, MASK_SOLID, &filter, &tr );
+ if ( tr.fraction < 1.0 )
+ {
+ // Calculate the point of intersection of the line (or hull) and the object we hit
+ // This is and approximation of the "best" intersection
+ CBaseEntity *pHit = tr.m_pEnt;
+ if ( !pHit || pHit->IsBSPModel() )
+ FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, pPlayer );
+ vecEnd = tr.endpos; // This is the point on the actual surface (the hull could have hit space)
+
+ // Make sure it is in front of us
+ Vector vecToEnd = vecEnd - vecSrc;
+ VectorNormalize( vecToEnd );
+
+ // if zero length, always hit
+ if ( vecToEnd.Length() > 0 )
+ {
+ float dot = DotProduct( vForward, vecToEnd );
+
+ // sanity that our hit is within range
+ if ( abs(dot) < 0.95 )
+ {
+ // fake that we actually missed
+ tr.fraction = 1.0;
+ }
+ }
+ }
+ }
+
+ WeaponSound( MELEE_MISS );
+
+ bool bDidHit = ( tr.fraction < 1.0f );
+
+ if ( bDidHit ) //if the swing hit
+ {
+ // delay the decal a bit
+ m_trHit = tr;
+
+ // Store the ent in an EHANDLE, just in case it goes away by the time we get into our think function.
+ m_pTraceHitEnt = tr.m_pEnt;
+
+ m_iSmackDamage = iDamageAmount;
+ m_iSmackDamageType = iDamageType;
+
+ m_flSmackTime = gpGlobals->curtime + flDmgDelay;
+ }
+
+ SendWeaponAnim( GetMeleeActivity() );
+
+ // player animation
+ pPlayer->DoAnimationEvent( PLAYERANIMEVENT_SECONDARY_ATTACK );
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + flAttackDelay;
+ m_flNextSecondaryAttack = gpGlobals->curtime + flAttackDelay;
+ m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
+
+#ifndef CLIENT_DLL
+ IGameEvent * event = gameeventmanager->CreateEvent( "dod_stats_weapon_attack" );
+ if ( event )
+ {
+ event->SetInt( "attacker", pPlayer->GetUserID() );
+ event->SetInt( "weapon", GetAltWeaponID() );
+
+ gameeventmanager->FireEvent( event );
+ }
+
+ lagcompensation->FinishLagCompensation( pPlayer );
+#endif //CLIENT_DLL
+
+ return tr.m_pEnt;
+}
+
+//Think function to delay the impact decal until the animation is finished playing
+void CWeaponDODBase::Smack()
+{
+ Assert( GetPlayerOwner() );
+
+ if ( !GetPlayerOwner() )
+ return;
+
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+ if ( !pPlayer )
+ return;
+
+ // Check that we are still facing the victim
+ Vector vForward, vRight, vUp;
+ AngleVectors( pPlayer->EyeAngles(), &vForward, &vRight, &vUp );
+ Vector vecSrc = pPlayer->Weapon_ShootPosition();
+ Vector vecEnd = vecSrc + vForward * 48;
+
+ CTraceFilterSimple filter( pPlayer, COLLISION_GROUP_NONE );
+
+ int iTraceMask = MASK_SOLID | CONTENTS_HITBOX | CONTENTS_DEBRIS;
+
+ trace_t tr;
+ UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &filter, &tr );
+
+ const float rayExtension = 40.0f;
+ UTIL_ClipTraceToPlayers( vecSrc, vecEnd + vForward * rayExtension, iTraceMask, &filter, &tr );
+
+ if ( tr.fraction >= 1.0 )
+ {
+ Vector head_hull_mins( -16, -16, -18 );
+ Vector head_hull_maxs( 16, 16, 18 );
+
+ UTIL_TraceHull( vecSrc, vecEnd, head_hull_mins, head_hull_maxs, MASK_SOLID, &filter, &tr );
+ if ( tr.fraction < 1.0 )
+ {
+ // Calculate the point of intersection of the line (or hull) and the object we hit
+ // This is and approximation of the "best" intersection
+ CBaseEntity *pHit = tr.m_pEnt;
+ if ( !pHit || pHit->IsBSPModel() )
+ FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, pPlayer );
+ vecEnd = tr.endpos; // This is the point on the actual surface (the hull could have hit space)
+ }
+ }
+
+ m_trHit = tr;
+
+ if ( !m_trHit.m_pEnt || (m_trHit.surface.flags & SURF_SKY) )
+ return;
+
+ if ( m_trHit.fraction == 1.0 )
+ return;
+
+ CPASAttenuationFilter attenuationFilter( this );
+ attenuationFilter.UsePredictionRules();
+
+ if( m_trHit.m_pEnt->IsPlayer() )
+ {
+ if ( m_iSmackDamageType & MELEE_DMG_STRONGATTACK )
+ WeaponSound( SPECIAL1 );
+ else
+ WeaponSound( MELEE_HIT );
+ }
+ else
+ WeaponSound( MELEE_HIT_WORLD );
+
+ int iDamageType = DMG_CLUB | DMG_NEVERGIB;
+
+#ifndef CLIENT_DLL
+ //if they hit the bounding box, just assume a chest hit
+ if( m_trHit.hitgroup == HITGROUP_GENERIC )
+ m_trHit.hitgroup = HITGROUP_CHEST;
+
+ float flDamage = (float)m_iSmackDamage;
+
+ CTakeDamageInfo info( pPlayer, pPlayer, flDamage, iDamageType );
+
+ if ( m_iSmackDamageType & MELEE_DMG_SECONDARYATTACK )
+ info.SetDamageCustom( MELEE_DMG_SECONDARYATTACK );
+
+ float flScale = (1.0f / flDamage) * dod_meleeattackforcescale.GetFloat();
+
+ Vector vecForceDir = vForward;
+
+ CalculateMeleeDamageForce( &info, vecForceDir, m_trHit.endpos, flScale );
+
+ Assert( m_trHit.m_pEnt != GetPlayerOwner() );
+
+ m_trHit.m_pEnt->DispatchTraceAttack( info, vForward, &m_trHit );
+ ApplyMultiDamage();
+#endif
+
+ // We've gotten minidumps where this happened.
+ if ( !GetPlayerOwner() )
+ return;
+
+ CEffectData data;
+ data.m_vOrigin = m_trHit.endpos;
+ data.m_vStart = m_trHit.startpos;
+ data.m_nSurfaceProp = m_trHit.surface.surfaceProps;
+ data.m_nHitBox = m_trHit.hitbox;
+#ifdef CLIENT_DLL
+ data.m_hEntity = m_trHit.m_pEnt->GetRefEHandle();
+#else
+ data.m_nEntIndex = m_trHit.m_pEnt->entindex();
+#endif
+
+ CPASFilter effectfilter( data.m_vOrigin );
+
+#ifndef CLIENT_DLL
+ effectfilter.RemoveRecipient( GetPlayerOwner() );
+#endif
+
+ data.m_vAngles = GetPlayerOwner()->GetAbsAngles();
+ data.m_fFlags = 0x1; //IMPACT_NODECAL;
+ data.m_nDamageType = iDamageType;
+
+ bool bHitPlayer = m_trHit.m_pEnt && m_trHit.m_pEnt->IsPlayer();
+
+ // don't do any impacts if we hit a teammate and ff is off
+ if ( bHitPlayer &&
+ m_trHit.m_pEnt->GetTeamNumber() == GetPlayerOwner()->GetTeamNumber() &&
+ !friendlyfire.GetBool() )
+ return;
+
+ if ( bHitPlayer )
+ {
+ te->DispatchEffect( effectfilter, 0.0, data.m_vOrigin, "Impact", data );
+ }
+ else if ( m_iSmackDamageType & MELEE_DMG_EDGE )
+ {
+ data.m_nDamageType = DMG_SLASH;
+ te->DispatchEffect( effectfilter, 0.0, data.m_vOrigin, "KnifeSlash", data );
+ }
+}
+
+#if defined( CLIENT_DLL )
+
+ float g_lateralBob = 0;
+ float g_verticalBob = 0;
+
+ static ConVar cl_bobcycle( "cl_bobcycle","0.8" );
+ static ConVar cl_bob( "cl_bob","0.002" );
+ static ConVar cl_bobup( "cl_bobup","0.5" );
+
+ // Register these cvars if needed for easy tweaking
+ static ConVar v_iyaw_cycle( "v_iyaw_cycle", "2"/*, FCVAR_UNREGISTERED*/ );
+ static ConVar v_iroll_cycle( "v_iroll_cycle", "0.5"/*, FCVAR_UNREGISTERED*/ );
+ static ConVar v_ipitch_cycle( "v_ipitch_cycle", "1"/*, FCVAR_UNREGISTERED*/ );
+ static ConVar v_iyaw_level( "v_iyaw_level", "0.3"/*, FCVAR_UNREGISTERED*/ );
+ static ConVar v_iroll_level( "v_iroll_level", "0.1"/*, FCVAR_UNREGISTERED*/ );
+ static ConVar v_ipitch_level( "v_ipitch_level", "0.3"/*, FCVAR_UNREGISTERED*/ );
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ // Output : float
+ //-----------------------------------------------------------------------------
+ float CWeaponDODBase::CalcViewmodelBob( void )
+ {
+ static float bobtime;
+ static float lastbobtime;
+ static float lastspeed;
+ float cycle;
+
+ CBasePlayer *player = ToBasePlayer( GetOwner() );
+ //Assert( player );
+
+ //NOTENOTE: For now, let this cycle continue when in the air, because it snaps badly without it
+
+ if ( ( !gpGlobals->frametime ) || ( player == NULL ) )
+ {
+ //NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!)
+ return 0.0f;// just use old value
+ }
+
+ //Find the speed of the player
+ float speed = player->GetLocalVelocity().Length2D();
+ float flmaxSpeedDelta = MAX( 0, (gpGlobals->curtime - lastbobtime) * 320.0f );
+
+ // don't allow too big speed changes
+ speed = clamp( speed, lastspeed-flmaxSpeedDelta, lastspeed+flmaxSpeedDelta );
+ speed = clamp( speed, -320, 320 );
+
+ lastspeed = speed;
+
+ //FIXME: This maximum speed value must come from the server.
+ // MaxSpeed() is not sufficient for dealing with sprinting - jdw
+
+ float bob_offset = RemapVal( speed, 0, 320, 0.0f, 1.0f );
+
+ bobtime += ( gpGlobals->curtime - lastbobtime ) * bob_offset;
+ lastbobtime = gpGlobals->curtime;
+
+ //Calculate the vertical bob
+ cycle = bobtime - (int)(bobtime/cl_bobcycle.GetFloat())*cl_bobcycle.GetFloat();
+ cycle /= cl_bobcycle.GetFloat();
+
+ if ( cycle < cl_bobup.GetFloat() )
+ {
+ cycle = M_PI * cycle / cl_bobup.GetFloat();
+ }
+ else
+ {
+ cycle = M_PI + M_PI*(cycle-cl_bobup.GetFloat())/(1.0 - cl_bobup.GetFloat());
+ }
+
+ g_verticalBob = speed*0.005f;
+ g_verticalBob = g_verticalBob*0.3 + g_verticalBob*0.7*sin(cycle);
+
+ g_verticalBob = clamp( g_verticalBob, -7.0f, 4.0f );
+
+ //Calculate the lateral bob
+ cycle = bobtime - (int)(bobtime/cl_bobcycle.GetFloat()*2)*cl_bobcycle.GetFloat()*2;
+ cycle /= cl_bobcycle.GetFloat()*2;
+
+ if ( cycle < cl_bobup.GetFloat() )
+ {
+ cycle = M_PI * cycle / cl_bobup.GetFloat();
+ }
+ else
+ {
+ cycle = M_PI + M_PI*(cycle-cl_bobup.GetFloat())/(1.0 - cl_bobup.GetFloat());
+ }
+
+ g_lateralBob = speed*0.005f;
+ g_lateralBob = g_lateralBob*0.3 + g_lateralBob*0.7*sin(cycle);
+ g_lateralBob = clamp( g_lateralBob, -7.0f, 4.0f );
+
+ //NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!)
+ return 0.0f;
+
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ // Input : &origin -
+ // &angles -
+ // viewmodelindex -
+ //-----------------------------------------------------------------------------
+ void CWeaponDODBase::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
+ {
+ Vector forward, right;
+ AngleVectors( angles, &forward, &right, NULL );
+
+ CalcViewmodelBob();
+
+ // Apply bob, but scaled down to 40%
+ VectorMA( origin, g_verticalBob * 0.4f, forward, origin );
+
+ // Z bob a bit more
+ origin[2] += g_verticalBob * 0.1f;
+
+ // bob the angles
+ angles[ ROLL ] += g_verticalBob * 0.5f;
+ angles[ PITCH ] -= g_verticalBob * 0.4f;
+
+ angles[ YAW ] -= g_lateralBob * 0.3f;
+
+ // VectorMA( origin, g_lateralBob * 0.2f, right, origin );
+ }
+
+ #include "c_te_effect_dispatch.h"
+
+ #define NUM_MUZZLE_FLASH_TYPES 4
+
+ bool CWeaponDODBase::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
+ {
+ if( event == 5001 )
+ {
+ if ( ShouldDrawMuzzleFlash() )
+ {
+ Assert( GetOwnerEntity() == C_BasePlayer::GetLocalPlayer() );
+
+ const char *pszMuzzleFlashEffect;
+
+ switch( GetDODWpnData().m_iMuzzleFlashType )
+ {
+ case DOD_MUZZLEFLASH_PISTOL:
+ pszMuzzleFlashEffect = "view_muzzle_pistols";
+ break;
+ case DOD_MUZZLEFLASH_AUTO:
+ pszMuzzleFlashEffect = "view_muzzle_fullyautomatic";
+ break;
+ case DOD_MUZZLEFLASH_RIFLE:
+ pszMuzzleFlashEffect = "view_muzzle_rifles";
+ break;
+ case DOD_MUZZLEFLASH_MG:
+ pszMuzzleFlashEffect = "view_muzzle_miniguns";
+ break;
+ case DOD_MUZZLEFLASH_ROCKET:
+ pszMuzzleFlashEffect = "view_muzzle_rockets";
+ break;
+ case DOD_MUZZLEFLASH_MG42:
+ pszMuzzleFlashEffect = "view_muzzle_mg42";
+ break;
+ default:
+ pszMuzzleFlashEffect = NULL;
+ break;
+ }
+
+ if ( pszMuzzleFlashEffect )
+ {
+ pViewModel->ParticleProp()->Create( pszMuzzleFlashEffect, PATTACH_POINT_FOLLOW, 1 );
+ }
+ }
+ return true;
+ }
+ else if( event == 6002 )
+ {
+ CEffectData data;
+ data.m_nHitBox = atoi( options );
+ data.m_hEntity = GetPlayerOwner() ? GetPlayerOwner()->GetRefEHandle() : INVALID_EHANDLE_INDEX;
+ pViewModel->GetAttachment( 2, data.m_vOrigin, data.m_vAngles );
+
+ DispatchEffect( "DOD_EjectBrass", data );
+ return true;
+ }
+
+ return BaseClass::OnFireEvent( pViewModel, origin, angles, event, options );
+ }
+
+ bool CWeaponDODBase::ShouldAutoEjectBrass( void )
+ {
+ // Don't eject brass if further than N units from the local player
+ C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pLocalPlayer )
+ return true;
+
+ float flMaxDistSqr = 250;
+ flMaxDistSqr *= flMaxDistSqr;
+
+ float flDistSqr = pLocalPlayer->EyePosition().DistToSqr( GetAbsOrigin() );
+ return ( flDistSqr < flMaxDistSqr );
+ }
+
+ bool CWeaponDODBase::GetEjectBrassShellType( void )
+ {
+ return 1;
+ }
+
+ void CWeaponDODBase::SetUseAltModel( bool bUseAltModel )
+ {
+ m_bUseAltWeaponModel = bUseAltModel;
+ }
+
+ void CWeaponDODBase::CheckForAltWeapon( int iCurrentState )
+ {
+ int iCriteria = GetDODWpnData().m_iAltWpnCriteria;
+
+ bool bUseAltModel = false;
+
+ if( ( iCriteria & iCurrentState ) != 0 )
+ bUseAltModel = true;
+
+ SetUseAltModel( bUseAltModel );
+ }
+
+ Vector CWeaponDODBase::GetDesiredViewModelOffset( C_DODPlayer *pOwner )
+ {
+ Vector viewOffset = pOwner->GetViewOffset();
+
+ float flPercent = ( viewOffset.z - VEC_PRONE_VIEW_SCALED( pOwner ).z ) / ( VEC_VIEW_SCALED( pOwner ).z - VEC_PRONE_VIEW_SCALED( pOwner ).z );
+
+ return ( flPercent * GetDODWpnData().m_vecViewNormalOffset +
+ ( 1.0 - flPercent ) * GetDODWpnData().m_vecViewProneOffset );
+ }
+
+ bool CWeaponDODBase::ShouldDraw( void )
+ {
+ if ( GetModel() == NULL )
+ {
+ // XXX(johns): Removed, doesn't seem to be the proper spot for this warning given that weapons can call
+ // ShouldDraw before their properties are filled.
+
+ // C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
+
+ // Warning( "BADNESS! Tell Matt that the weapon '%s' tried to draw with a null model ( %d, %d, %s ) \n",
+ // GetDODWpnData().szClassName,
+ // m_iWorldModelIndex.Get(), m_iReloadModelIndex.Get(), m_bUseAltWeaponModel ? "alt" : "not alt" );
+
+ return false;
+ }
+
+ return BaseClass::ShouldDraw();
+ }
+
+#else
+
+ void CWeaponDODBase::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
+ {
+
+ }
+
+ float CWeaponDODBase::CalcViewmodelBob( void )
+ {
+ return 0.0f;
+ }
+
+ void CWeaponDODBase::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
+ {
+ if ( CanDrop() == false )
+ return;
+
+ CDODPlayer *pPlayer = ToDODPlayer( pActivator );
+
+ if ( pPlayer )
+ {
+ pPlayer->PickUpWeapon( this );
+ }
+ }
+
+#endif
+
diff --git a/game/shared/dod/weapon_dodbase.h b/game/shared/dod/weapon_dodbase.h
new file mode 100644
index 0000000..51cf97e
--- /dev/null
+++ b/game/shared/dod/weapon_dodbase.h
@@ -0,0 +1,403 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WEAPON_DODBASE_H
+#define WEAPON_DODBASE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "dod_playeranimstate.h"
+#include "dod_weapon_parse.h"
+
+#if defined( CLIENT_DLL )
+ #define CWeaponDODBase C_WeaponDODBase
+#endif
+
+extern int AliasToWeaponID( const char *alias );
+extern const char *WeaponIDToAlias( int id );
+extern bool IsPrimaryWeapon( int id );
+extern bool IsSecondaryWeapon( int id );
+
+class CDODPlayer;
+
+// These are the names of the ammo types that go in the CAmmoDefs and that the
+// weapon script files reference.
+
+#define DOD_AMMO_SUBMG "DOD_AMMO_SUBMG"
+#define DOD_AMMO_ROCKET "DOD_AMMO_ROCKET"
+#define DOD_AMMO_COLT "DOD_AMMO_COLT"
+#define DOD_AMMO_P38 "DOD_AMMO_P38"
+#define DOD_AMMO_C96 "DOD_AMMO_C96"
+#define DOD_AMMO_WEBLEY "DOD_AMMO_WEBLEY"
+#define DOD_AMMO_GARAND "DOD_AMMO_GARAND"
+#define DOD_AMMO_K98 "DOD_AMMO_K98"
+#define DOD_AMMO_M1CARBINE "DOD_AMMO_M1CARBINE"
+#define DOD_AMMO_ENFIELD "DOD_AMMO_ENFIELD"
+#define DOD_AMMO_SPRING "DOD_AMMO_SPRING"
+#define DOD_AMMO_FG42 "DOD_AMMO_FG42"
+#define DOD_AMMO_BREN "DOD_AMMO_BREN"
+#define DOD_AMMO_BAR "DOD_AMMO_BAR"
+#define DOD_AMMO_30CAL "DOD_AMMO_30CAL"
+#define DOD_AMMO_MG34 "DOD_AMMO_MG34"
+#define DOD_AMMO_MG42 "DOD_AMMO_MG42"
+#define DOD_AMMO_HANDGRENADE "DOD_AMMO_HANDGRENADE"
+#define DOD_AMMO_HANDGRENADE_EX "DOD_AMMO_HANDGRENADE_EX" // the EX is for EXploding! :)
+#define DOD_AMMO_STICKGRENADE "DOD_AMMO_STICKGRENADE"
+#define DOD_AMMO_STICKGRENADE_EX "DOD_AMMO_STICKGRENADE_EX"
+#define DOD_AMMO_SMOKEGRENADE_US "DOD_AMMO_SMOKEGRENADE_US"
+#define DOD_AMMO_SMOKEGRENADE_GER "DOD_AMMO_SMOKEGRENADE_GER"
+#define DOD_AMMO_SMOKEGRENADE_US_LIVE "DOD_AMMO_SMOKEGRENADE_US_LIVE"
+#define DOD_AMMO_SMOKEGRENADE_GER_LIVE "DOD_AMMO_SMOKEGRENADE_GER_LIVE"
+#define DOD_AMMO_RIFLEGRENADE_US "DOD_AMMO_RIFLEGRENADE_US"
+#define DOD_AMMO_RIFLEGRENADE_GER "DOD_AMMO_RIFLEGRENADE_GER"
+#define DOD_AMMO_RIFLEGRENADE_US_LIVE "DOD_AMMO_RIFLEGRENADE_US_LIVE"
+#define DOD_AMMO_RIFLEGRENADE_GER_LIVE "DOD_AMMO_RIFLEGRENADE_GER_LIVE"
+
+
+
+#define CROSSHAIR_CONTRACT_PIXELS_PER_SECOND 7.0f
+
+// Given an ammo type (like from a weapon's GetPrimaryAmmoType()), this compares it
+// against the ammo name you specify.
+// MIKETODO: this should use indexing instead of searching and strcmp()'ing all the time.
+bool IsAmmoType( int iAmmoType, const char *pAmmoName );
+
+
+typedef enum
+{
+ WEAPON_NONE = 0,
+
+ //Melee
+ WEAPON_AMERKNIFE,
+ WEAPON_SPADE,
+
+ //Pistols
+ WEAPON_COLT,
+ WEAPON_P38,
+ WEAPON_C96,
+
+ //Rifles
+ WEAPON_GARAND,
+ WEAPON_M1CARBINE,
+ WEAPON_K98,
+
+ //Sniper Rifles
+ WEAPON_SPRING,
+ WEAPON_K98_SCOPED,
+
+ //SMG
+ WEAPON_THOMPSON,
+ WEAPON_MP40,
+ WEAPON_MP44,
+ WEAPON_BAR,
+
+ //Machine guns
+ WEAPON_30CAL,
+ WEAPON_MG42,
+
+ //Rocket weapons
+ WEAPON_BAZOOKA,
+ WEAPON_PSCHRECK,
+
+ //Grenades
+ WEAPON_FRAG_US,
+ WEAPON_FRAG_GER,
+
+ WEAPON_FRAG_US_LIVE,
+ WEAPON_FRAG_GER_LIVE,
+
+ WEAPON_SMOKE_US,
+ WEAPON_SMOKE_GER,
+
+ WEAPON_RIFLEGREN_US,
+ WEAPON_RIFLEGREN_GER,
+
+ WEAPON_RIFLEGREN_US_LIVE,
+ WEAPON_RIFLEGREN_GER_LIVE,
+
+ // not actually separate weapons, but defines used in stats recording
+ // find a better way to do this without polluting the list of actual weapons.
+ WEAPON_THOMPSON_PUNCH,
+ WEAPON_MP40_PUNCH,
+
+ WEAPON_GARAND_ZOOMED,
+ WEAPON_K98_ZOOMED,
+ WEAPON_SPRING_ZOOMED,
+ WEAPON_K98_SCOPED_ZOOMED,
+
+ WEAPON_30CAL_UNDEPLOYED,
+ WEAPON_MG42_UNDEPLOYED,
+
+ WEAPON_BAR_SEMIAUTO,
+ WEAPON_MP44_SEMIAUTO,
+
+ WEAPON_MAX, // number of weapons weapon index
+
+} DODWeaponID;
+
+
+//Class Heirarchy for dod weapons
+
+/*
+
+ CWeaponDODBase
+ |
+ |
+ |--> CWeaponDODBaseMelee
+ | |
+ | |--> CWeaponSpade
+ | |--> CWeaponUSKnife
+ |
+ |--> CWeaponDODBaseGrenade
+ | |
+ | |--> CWeaponHandgrenade
+ | |--> CWeaponStickGrenade
+ | |--> CWeaponSmokeGrenadeUS
+ | |--> CWeaponSmokeGrenadeGER
+ |
+ |--> CWeaponBaseRifleGrenade
+ | |
+ | |--> CWeaponRifleGrenadeUS
+ | |--> CWeaponRifleGrenadeGER
+ |
+ |--> CDODBaseRocketWeapon
+ | |
+ | |--> CWeaponBazooka
+ | |--> CWeaponPschreck
+ |
+ |--> CWeaponDODBaseGun
+ |
+ |--> CDODFullAutoWeapon
+ | |
+ | |--> CWeaponC96
+ | |
+ | |--> CDODFullAutoPunchWeapon
+ | | |
+ | | |--> CWeaponThompson
+ | | |--> CWeaponMP40
+ | |
+ | |--> CDODBipodWeapon
+ | |
+ | |-> CWeapon30Cal
+ | |-> CWeaponMG42
+ |
+ |--> CDODFireSelectWeapon
+ | |
+ | |--> CWeaponMP44
+ | |--> CWeaponBAR
+ |
+ |
+ |--> CDODSemiAutoWeapon
+ |
+ |--> CWeaponColt
+ |--> CWeaponP38
+ |--> CWeaponM1Carbine
+ |--> CDODSniperWeapon
+ |
+ |--> CWeaponSpring
+ |--> CWeaponScopedK98
+ |--> CWeaponGarand
+ |--> CWeaponK98
+
+*/
+
+void FindHullIntersection( const Vector &vecSrc, trace_t &tr, const Vector &mins, const Vector &maxs, CBaseEntity *pEntity );
+
+typedef enum
+{
+ Primary_Mode = 0,
+ Secondary_Mode,
+} DODWeaponMode;
+
+
+class CWeaponDODBase : public CBaseCombatWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponDODBase, CBaseCombatWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CWeaponDODBase();
+
+ #ifdef GAME_DLL
+ DECLARE_DATADESC();
+
+ virtual void CheckRespawn();
+ virtual CBaseEntity* Respawn();
+
+ virtual const Vector& GetBulletSpread();
+ virtual float GetDefaultAnimSpeed();
+
+ virtual void ItemBusyFrame();
+ virtual bool ShouldRemoveOnRoundRestart();
+
+ void Materialize();
+ void AttemptToMaterialize();
+
+ #else
+
+ void PlayWorldReloadSound( CDODPlayer *pPlayer );
+
+ #endif
+
+ virtual bool DefaultReload( int iClipSize1, int iClipSize2, int iActivity );
+
+ virtual bool Holster( CBaseCombatWeapon *pSwitchingTo );
+ virtual void Drop( const Vector &vecVelocity );
+ virtual void AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles );
+ virtual float CalcViewmodelBob( void );
+ // All predicted weapons need to implement and return true
+ virtual bool IsPredicted() const;
+
+ virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | FCAP_USE_IN_RADIUS; }
+
+ CBasePlayer* GetPlayerOwner() const;
+ CDODPlayer* GetDODPlayerOwner() const;
+
+ virtual void WeaponIdle( void );
+ virtual Activity GetIdleActivity( void );
+
+ // Get DOD-specific weapon data.
+ CDODWeaponInfo const &GetDODWpnData() const;
+
+ // Get specific DOD weapon ID (ie: WEAPON_GARAND, etc)
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_NONE; }
+ virtual DODWeaponID GetStatsWeaponID( void ) { return GetWeaponID(); }
+ virtual DODWeaponID GetAltWeaponID( void ) const { return WEAPON_NONE; }
+
+ // return true if this weapon is an instance of the given weapon type (ie: "IsA" WEAPON_GLOCK)
+ bool IsA( DODWeaponID id ) const { return GetWeaponID() == id; }
+
+ // return true if this weapon has a silencer equipped
+ virtual bool IsSilenced( void ) const { return false; }
+
+ void KickBack( float up_base, float lateral_base, float up_modifier, float lateral_modifier, float up_max, float lateral_max, int direction_change );
+
+ virtual void SetWeaponModelIndex( const char *pName );
+
+ virtual bool CanDrop( void ) { return false; }
+
+ virtual bool ShouldDrawCrosshair( void ) { return true; }
+ virtual bool ShouldDrawViewModel( void ) { return true; }
+ virtual bool ShouldDrawMuzzleFlash( void ) { return true; }
+
+ virtual float GetWeaponAccuracy( float flPlayerSpeed ) { return 0; }
+
+ virtual bool HideViewModelWhenZoomed( void ) { return false; }
+
+ virtual bool CanAttack( void );
+ virtual bool ShouldAutoReload( void );
+
+ CNetworkVar( int, m_iReloadModelIndex );
+ CNetworkVector( m_vInitialDropVelocity );
+
+ virtual void FinishReload( void ) {}
+
+public:
+ #if defined( CLIENT_DLL )
+
+ virtual void ProcessMuzzleFlashEvent();
+ virtual bool ShouldPredict();
+
+
+ virtual void PostDataUpdate( DataUpdateType_t type );
+ virtual void OnDataChanged( DataUpdateType_t type );
+
+ virtual bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options );
+
+ virtual bool ShouldAutoEjectBrass( void );
+ virtual bool GetEjectBrassShellType( void );
+
+ void SetUseAltModel( bool bUseAlt );
+ virtual int GetWorldModelIndex( void );
+ virtual void CheckForAltWeapon( int iCurrentState );
+
+ virtual Vector GetDesiredViewModelOffset( C_DODPlayer *pOwner );
+ virtual float GetViewModelSwayScale( void ) { return 1.0; }
+
+ virtual void OnWeaponDropped( void ) {}
+
+ virtual bool ShouldDraw( void );
+
+ float m_flCrosshairDistance;
+ int m_iAmmoLastCheck;
+ int m_iAlpha;
+ int m_iScopeTextureID;
+
+ bool m_bUseAltWeaponModel; //use alternate left handed world model? reset on new sequence
+ #else
+
+ virtual bool Reload();
+ virtual void Spawn();
+
+ void SetDieThink( bool bDie );
+ void Die( void );
+
+ void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
+
+ #endif
+
+ virtual void OnPickedUp( CBaseCombatCharacter *pNewOwner );
+
+ bool IsUseable();
+ virtual bool CanDeploy( void );
+ virtual bool CanHolster( void );
+ virtual bool SendWeaponAnim( int iActivity );
+ virtual void Precache( void );
+ virtual bool CanBeSelected( void );
+ virtual bool DefaultDeploy( char *szViewModel, char *szWeaponModel, int iActivity, char *szAnimExt );
+ virtual bool Deploy();
+ bool PlayEmptySound();
+ virtual void ItemPostFrame();
+
+ virtual const char *GetViewModel( int viewmodelindex = 0 ) const;
+
+ bool m_bInAttack; //True after a semi-auto weapon fires - will not fire a second time on the same button press
+
+ void SetExtraAmmoCount( int count ) { m_iExtraPrimaryAmmo = count; }
+ int GetExtraAmmoCount( void ) { return m_iExtraPrimaryAmmo; }
+
+ virtual const char *GetSecondaryDeathNoticeName( void ) { return "world"; }
+
+ virtual CBaseEntity *MeleeAttack( int iDamageAmount, int iDamageType, float flDmgDelay, float flAttackDelay );
+ void EXPORT Smack( void );
+ //Secondary Attacks
+ void RifleButt( void );
+ void Bayonet( void );
+ void Punch( void );
+
+ virtual Activity GetMeleeActivity( void ) { return ACT_VM_SECONDARYATTACK; }
+ virtual Activity GetStrongMeleeActivity( void ) { return ACT_VM_SECONDARYATTACK; }
+
+ virtual float GetRecoil( void ) { return 0.0f; }
+
+protected:
+ CNetworkVar( float, m_flSmackTime );
+ int m_iSmackDamage;
+ int m_iSmackDamageType;
+ EHANDLE m_pTraceHitEnt;
+ trace_t m_trHit;
+
+ int m_iAltFireHint;
+
+private:
+
+ void EjectBrassLate();
+
+ float m_flDecreaseShotsFired;
+
+ CWeaponDODBase( const CWeaponDODBase & );
+
+ int m_iExtraPrimaryAmmo;
+
+#ifdef CLIENT_DLL
+ int m_iCrosshairTexture;
+#endif
+};
+
+
+#endif // WEAPON_DODBASE_H
diff --git a/game/shared/dod/weapon_dodbasebomb.cpp b/game/shared/dod/weapon_dodbasebomb.cpp
new file mode 100644
index 0000000..a6a9786
--- /dev/null
+++ b/game/shared/dod/weapon_dodbasebomb.cpp
@@ -0,0 +1,375 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasebomb.h"
+
+
+#ifdef CLIENT_DLL
+ #include "c_dod_player.h"
+#else
+ #include "dod_player.h"
+ #include "dod_bombtarget.h"
+ #include "collisionutils.h"
+ #include "in_buttons.h"
+#endif
+
+
+IMPLEMENT_NETWORKCLASS_ALIASED( DODBaseBombWeapon, DT_BaseBombWeapon )
+
+
+BEGIN_NETWORK_TABLE( CDODBaseBombWeapon, DT_BaseBombWeapon )
+
+#ifdef CLIENT_DLL
+ //RecvPropBool( RECVINFO(m_bDeployed) )
+#else
+ //SendPropBool( SENDINFO(m_bDeployed) )
+#endif
+
+END_NETWORK_TABLE()
+
+
+BEGIN_PREDICTION_DATA( CDODBaseBombWeapon )
+END_PREDICTION_DATA()
+
+#ifndef CLIENT_DLL
+
+BEGIN_DATADESC( CDODBaseBombWeapon )
+END_DATADESC()
+
+#endif
+
+LINK_ENTITY_TO_CLASS( weapon_basebomb, CDODBaseBombWeapon );
+PRECACHE_WEAPON_REGISTER( weapon_basebomb );
+
+acttable_t CDODBaseBombWeapon::m_acttable[] =
+{
+ { ACT_PRONE_IDLE, ACT_DOD_PRONEWALK_IDLE_PISTOL, false }, //?
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_PISTOL, false }, //?
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_TNT, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_TNT, false }, //?
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_TNT, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_TNT, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_TNT, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_TNT, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_PISTOL, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_PISTOL, false },
+};
+
+IMPLEMENT_ACTTABLE( CDODBaseBombWeapon );
+
+CDODBaseBombWeapon::CDODBaseBombWeapon()
+{
+}
+
+void CDODBaseBombWeapon::Spawn( )
+{
+ WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( GetClassname() );
+
+ Assert( hWpnInfo != GetInvalidWeaponInfoHandle() );
+
+ CDODWeaponInfo *pWeaponInfo = dynamic_cast< CDODWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
+
+ Assert( pWeaponInfo && "Failed to get CDODWeaponInfo in weapon spawn" );
+
+ m_pWeaponInfo = pWeaponInfo;
+
+ SetPlanting( false );
+
+ BaseClass::Spawn();
+}
+
+void CDODBaseBombWeapon::Precache()
+{
+ BaseClass::Precache();
+}
+
+bool CDODBaseBombWeapon::Deploy( )
+{
+#ifdef CLIENT_DLL
+ CDODPlayer *pPlayer = GetDODPlayerOwner();
+
+ if ( pPlayer )
+ {
+ pPlayer->HintMessage( HINT_BOMB_FIRST_SELECT );
+ }
+#endif
+
+ return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), GetDrawActivity(), (char*)GetAnimPrefix() );
+}
+
+void CDODBaseBombWeapon::PrimaryAttack()
+{
+#ifndef CLIENT_DLL
+ if ( IsPlanting() )
+ {
+ CDODBombTarget *pTarget = (CDODBombTarget *)m_hBombTarget.Get();
+ CBasePlayer *pPlayer = GetPlayerOwner();
+
+ if ( !pTarget || !pPlayer )
+ {
+ CancelPlanting();
+ return;
+ }
+
+ if ( pTarget->CanPlantHere( GetDODPlayerOwner() ) == false )
+ {
+ // if the target is not active anymore, cancel ( someone planted there already? )
+ CancelPlanting();
+ }
+ else if ( ( pTarget->GetAbsOrigin() - pPlayer->WorldSpaceCenter() ).Length() > DOD_BOMB_PLANT_RADIUS )
+ {
+ // if we're too far away, cancel
+ CancelPlanting();
+ }
+ else if ( IsLookingAtBombTarget( pPlayer, pTarget ) == false || ( pPlayer->GetFlags() & FL_ONGROUND ) == 0 )
+ {
+ // not looking at the target anymore
+ CancelPlanting();
+ }
+ else if ( gpGlobals->curtime > m_flPlantCompleteTime )
+ {
+ // we finished the plant
+ CompletePlant();
+ }
+ else
+ {
+ m_flNextPlantCheck = gpGlobals->curtime + 0.2;
+ }
+
+ return;
+ }
+
+ // find nearby, visible bomb targets
+ CBaseEntity *pEnt = NULL;
+ CDODBombTarget *pBestTarget = NULL;
+
+ float flBestDist = FLT_MAX;
+
+ CDODPlayer *pPlayer = GetDODPlayerOwner();
+
+ if ( !pPlayer )
+ return;
+
+ while( ( pEnt = gEntList.FindEntityByClassname( pEnt, "dod_bomb_target" ) ) != NULL )
+ {
+ CDODBombTarget *pTarget = static_cast<CDODBombTarget *>( pEnt );
+
+ if ( !pTarget->CanPlantHere( pPlayer ) )
+ continue;
+
+ Vector pos = pPlayer->WorldSpaceCenter();
+
+ float flDist = ( pos - pTarget->GetAbsOrigin() ).Length();
+
+ // if we are looking directly at a bomb target and it is within our radius, that automatically wins
+ if ( flDist < flBestDist &&
+ flDist < DOD_BOMB_PLANT_RADIUS &&
+ IsLookingAtBombTarget( pPlayer, pTarget ) &&
+ ( pPlayer->GetFlags() & FL_ONGROUND ) )
+ {
+ flBestDist = flDist;
+ pBestTarget = pTarget;
+ }
+ }
+
+ if ( pBestTarget )
+ {
+ StartPlanting( pBestTarget );
+ }
+
+ m_flNextPlantCheck = gpGlobals->curtime + 0.2;
+
+ // true if the player is not holding primary attack
+ m_bUsePlant = !( pPlayer->m_nButtons & (IN_ATTACK|IN_ATTACK2) );
+#endif
+}
+
+void CDODBaseBombWeapon::SecondaryAttack()
+{
+ PrimaryAttack();
+}
+
+#ifndef CLIENT_DLL
+void CDODBaseBombWeapon::StartPlanting( CDODBombTarget *pTarget )
+{
+ // we have already checked that we can plant here
+
+ // store a pointer to the target we're bombing
+ m_hBombTarget = pTarget;
+
+ // must do this after setting the bomb target as we tell the planter
+ // what target they are at
+ SetPlanting( true );
+
+ // set the timer for when we'll be done
+ m_flPlantCompleteTime = gpGlobals->curtime + DOD_BOMB_PLANT_TIME;
+
+ // play the planting animation
+ SendWeaponAnim( ACT_VM_PRIMARYATTACK );
+
+ CDODPlayer *pPlayer = GetDODPlayerOwner();
+
+ if ( pPlayer )
+ {
+ pPlayer->DoAnimationEvent( PLAYERANIMEVENT_PLANT_TNT );
+
+ pPlayer->SetMaxSpeed( 1 );
+
+ pPlayer->SetProgressBarTime( DOD_BOMB_PLANT_TIME );
+ }
+}
+
+bool CDODBaseBombWeapon::CancelPlanting( void )
+{
+ bool bHolster = false;
+
+ SetPlanting( false );
+
+ // play a stop animation
+ SendWeaponAnim( ACT_VM_IDLE );
+
+ CDODPlayer *pPlayer = GetDODPlayerOwner();
+
+ if ( pPlayer )
+ {
+ pPlayer->DoAnimationEvent( PLAYERANIMEVENT_CANCEL_GESTURES );
+
+ // restore player speed
+ pPlayer->SetMaxSpeed( 600 );
+
+ pPlayer->ResetProgressBar();
+
+ if ( m_bUsePlant )
+ {
+ pPlayer->SelectLastItem();
+
+ bHolster = true;
+ }
+ }
+
+ return bHolster;
+}
+
+void CDODBaseBombWeapon::CompletePlant( void )
+{
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+ if ( pPlayer )
+ {
+ SetPlanting( false );
+
+ // restore player speed
+ GetDODPlayerOwner()->SetMaxSpeed( 600 );
+
+ // Tell the target that we finished planting the bomb
+ ((CDODBombTarget *)m_hBombTarget.Get())->CompletePlanting( pPlayer );
+
+ // destroy the bomb weapon
+ pPlayer->Weapon_Drop( this, NULL, NULL );
+ UTIL_Remove(this);
+
+ pPlayer->ResetProgressBar();
+
+ pPlayer->SelectLastItem();
+ }
+}
+
+bool CDODBaseBombWeapon::IsLookingAtBombTarget( CBasePlayer *pPlayer, CDODBombTarget *pTarget )
+{
+ Vector forward;
+ AngleVectors( pPlayer->EyeAngles(), &forward );
+
+ Vector toBomb = pTarget->GetAbsOrigin() - pPlayer->EyePosition();
+ toBomb.NormalizeInPlace();
+
+ return ( DotProduct( forward, toBomb ) >= 0.8 );
+}
+
+#endif
+
+void CDODBaseBombWeapon::ItemPostFrame()
+{
+#ifndef CLIENT_DLL
+ CBasePlayer *pPlayer = GetPlayerOwner();
+
+ if ( !pPlayer )
+ return;
+
+ if ( pPlayer->m_nButtons & (IN_ATTACK|IN_ATTACK2) )
+ {
+ PrimaryAttack();
+ }
+ // Only use the time check if we are planting with the +use key
+ // adds a slight lag to breaking the player lock otherwise
+ else if ( !m_bUsePlant || m_flNextPlantCheck < gpGlobals->curtime )
+ {
+ if ( IsPlanting() )
+ {
+ // reset all planting
+ bool bHolster = CancelPlanting();
+
+ // sometimes after canceling we put the weapon away and switch
+ // to our last weapon. In that case, we don't want to send any more
+ // anim calls b/c it confuses the client.
+ if ( bHolster )
+ {
+ // we've put this weapon away, stop everything
+ return;
+ }
+
+ // anim now
+ m_flTimeWeaponIdle = 0;
+ }
+
+ // idle
+ if (m_flTimeWeaponIdle > gpGlobals->curtime)
+ return;
+
+ SendWeaponAnim( GetIdleActivity() );
+
+ m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
+
+ // if we're not planting, why do we have the bomb out?
+ // switch to our next best weapon
+ pPlayer->SelectLastItem();
+ }
+
+#endif // CLIENT_DLL
+}
+
+bool CDODBaseBombWeapon::Holster( CBaseCombatWeapon *pSwitchingTo )
+{
+#ifndef CLIENT_DLL
+ if ( IsPlanting() )
+ CancelPlanting();
+#endif
+
+ return BaseClass::Holster( pSwitchingTo );
+}
+
+void CDODBaseBombWeapon::SetPlanting( bool bPlanting )
+{
+ m_bPlanting = bPlanting;
+
+#ifndef CLIENT_DLL
+ CDODPlayer *pPlayer = GetDODPlayerOwner();
+
+ if ( pPlayer )
+ {
+ pPlayer->SetPlanting( m_bPlanting ? (CDODBombTarget *)m_hBombTarget.Get() : NULL );
+ }
+#endif
+}
+
+bool CDODBaseBombWeapon::IsPlanting( void )
+{
+ return m_bPlanting;
+} \ No newline at end of file
diff --git a/game/shared/dod/weapon_dodbasebomb.h b/game/shared/dod/weapon_dodbasebomb.h
new file mode 100644
index 0000000..2894b64
--- /dev/null
+++ b/game/shared/dod/weapon_dodbasebomb.h
@@ -0,0 +1,87 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef WEAPON_DODBASEBOMB_H
+#define WEAPON_DODBASEBOMB_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "weapon_dodbase.h"
+
+#if defined( CLIENT_DLL )
+
+#define CDODBaseBombWeapon C_DODBaseBombWeapon
+
+#else
+
+#include "dod_bombtarget.h"
+
+#endif
+
+//-----------------------------------------------------------------------------
+// RPG
+//-----------------------------------------------------------------------------
+class CDODBaseBombWeapon : public CWeaponDODBase
+{
+public:
+ DECLARE_CLASS( CDODBaseBombWeapon, CWeaponDODBase );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CDODBaseBombWeapon();
+
+ virtual void Spawn();
+ virtual void Precache( void );
+ virtual bool Deploy();
+ virtual void PrimaryAttack();
+ virtual void SecondaryAttack();
+ virtual bool Holster( CBaseCombatWeapon *pSwitchingTo );
+
+ virtual void ItemPostFrame( void );
+
+ virtual bool CanDrop( void ) { return false; }
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_NONE; }
+ virtual bool ShouldDrawCrosshair( void ) { return false; }
+ virtual bool HasPrimaryAmmo() { return true; }
+ virtual bool CanBeSelected() { return false; }
+
+#ifndef CLIENT_DLL
+ void StartPlanting( CDODBombTarget *pTarget );
+ bool CancelPlanting( void );
+ void CompletePlant( void );
+ bool IsLookingAtBombTarget( CBasePlayer *pPlayer, CDODBombTarget *pTarget );
+#endif
+
+ void SetPlanting( bool bPlanting );
+ bool IsPlanting( void );
+
+protected:
+ CDODWeaponInfo *m_pWeaponInfo;
+
+private:
+ CDODBaseBombWeapon( const CDODBaseBombWeapon & );
+
+ bool m_bPlanting;
+
+ // pointer to the dod_bomb_target that we're planting at
+ EHANDLE m_hBombTarget;
+
+ // when the plant will be complete
+ float m_flPlantCompleteTime;
+
+ bool m_bUsePlant; // player hit +use to start this plant
+ float m_flNextPlantCheck;
+
+#ifndef CLIENT_DLL
+ DECLARE_DATADESC();
+#endif
+};
+
+#endif // WEAPON_DODBASEBOMB_H \ No newline at end of file
diff --git a/game/shared/dod/weapon_dodbasegrenade.cpp b/game/shared/dod/weapon_dodbasegrenade.cpp
new file mode 100644
index 0000000..d04255a
--- /dev/null
+++ b/game/shared/dod/weapon_dodbasegrenade.cpp
@@ -0,0 +1,474 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasegrenade.h"
+#include "in_buttons.h"
+#include "dod_gamerules.h"
+
+
+#if defined( CLIENT_DLL )
+ #include "c_dod_player.h"
+#else
+ #include "dod_player.h"
+#endif
+
+extern ConVar dod_bonusround;
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponDODBaseGrenade, DT_WeaponDODBaseGrenade )
+
+BEGIN_NETWORK_TABLE(CWeaponDODBaseGrenade, DT_WeaponDODBaseGrenade)
+#if !defined( CLIENT_DLL )
+ SendPropBool( SENDINFO( m_bPinPulled ) ),
+ SendPropBool( SENDINFO( m_bArmed ) ),
+#else
+ RecvPropBool( RECVINFO( m_bPinPulled ) ),
+ RecvPropBool( RECVINFO( m_bArmed ) ),
+#endif
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponDODBaseGrenade )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_basedodgrenade, CWeaponDODBaseGrenade );
+
+acttable_t CWeaponDODBaseGrenade::m_acttable[] =
+{
+ // Move this out to the specific grenades???
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_GREN_FRAG, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_GREN_FRAG, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_GREN_FRAG, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_GREN_FRAG, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_GREN_FRAG, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_GREN_FRAG, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_AIM_GREN_FRAG, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_AIM_GREN_FRAG, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_AIM_GREN_FRAG, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_AIM_GREN_FRAG, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_AIM_GREN_FRAG, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_AIM_GREN_FRAG, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_AIM_GREN_FRAG, false },
+
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_GREN_FRAG, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_GREN_FRAG, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_CROUCH_GREN_FRAG, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_STICKGRENADE, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_STICKGRENADE, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponDODBaseGrenade );
+
+CWeaponDODBaseGrenade::CWeaponDODBaseGrenade()
+{
+ m_bRedraw = false;
+ m_bPinPulled = false;
+ SetArmed( false );
+
+ m_iAltFireHint = HINT_USE_PRIME;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CWeaponDODBaseGrenade::CanHolster( void )
+{
+ // can only holster hand grenades when not primed!
+ return ( m_bPinPulled == false && !IsArmed() );
+}
+
+#ifdef CLIENT_DLL
+
+ void CWeaponDODBaseGrenade::PrimaryAttack()
+ {
+ //nothing on the client
+ }
+
+#else
+
+ BEGIN_DATADESC( CWeaponDODBaseGrenade )
+ DEFINE_FIELD( m_bRedraw, FIELD_BOOLEAN ),
+ DEFINE_INPUTFUNC( FIELD_FLOAT, "DetonateTime", InputSetDetonateTime ),
+ END_DATADESC()
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ void CWeaponDODBaseGrenade::Precache()
+ {
+ PrecacheScriptSound( "Weapon_Grenade.Throw" );
+
+ // Precache all the grenade minimap icons.
+ PrecacheMaterial( "sprites/minimap_icons/minimap_riflegren_ger" );
+ PrecacheMaterial( "sprites/minimap_icons/minimap_riflegren_us" );
+ PrecacheMaterial( "sprites/minimap_icons/grenade_hltv" );
+ PrecacheMaterial( "sprites/minimap_icons/stick_hltv" );
+ PrecacheMaterial( "sprites/minimap_icons/minimap_smoke_us" );
+ PrecacheMaterial( "sprites/minimap_icons/minimap_smoke_ger" );
+
+ BaseClass::Precache();
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ bool CWeaponDODBaseGrenade::Deploy()
+ {
+ m_bRedraw = false;
+ m_bPinPulled = false;
+
+ return BaseClass::Deploy();
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ // Output : Returns true on success, false on failure.
+ //-----------------------------------------------------------------------------
+ bool CWeaponDODBaseGrenade::Holster( CBaseCombatWeapon *pSwitchingTo )
+ {
+ m_bRedraw = false;
+
+#ifndef CLIENT_DLL
+ // If they attempt to switch weapons before the throw animation is done,
+ // allow it, but kill the weapon if we have to.
+
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+ if( pPlayer && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
+ {
+ pPlayer->Weapon_Drop( this, NULL, NULL );
+ UTIL_Remove(this);
+ }
+#endif
+
+ return BaseClass::Holster( pSwitchingTo );
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ // Output : Returns true on success, false on failure.
+ //-----------------------------------------------------------------------------
+ bool CWeaponDODBaseGrenade::Reload()
+ {
+ if ( ( m_bRedraw ) && ( m_flNextPrimaryAttack <= gpGlobals->curtime ) && ( m_flNextSecondaryAttack <= gpGlobals->curtime ) )
+ {
+ //Redraw the weapon
+ SendWeaponAnim( GetDrawActivity() );
+
+ //Update our times
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+ m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
+ m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
+
+ //Mark this as done
+ m_bRedraw = false;
+ }
+
+ return true;
+ }
+
+enum
+{
+ THROW_THROW = 0,
+ THROW_PRIME
+};
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ void CWeaponDODBaseGrenade::PrimaryAttack()
+ {
+ if ( IsArmed() ) // live grenade already?
+ {
+ StartThrow( THROW_THROW );
+ }
+ else
+ {
+ StartThrow( THROW_PRIME );
+ }
+ }
+
+ void CWeaponDODBaseGrenade::StartThrow( int throwType )
+ {
+ if( GetPlayerOwner()->GetWaterLevel() > 2 )
+ {
+ PlayEmptySound();
+ m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
+ return;
+ }
+
+ if ( !m_bPinPulled )
+ {
+ m_bPinPulled = true;
+
+ SendWeaponAnim( GetPrimaryAttackActivity() );
+
+ // Can't prime an already primed grenade!
+ if ( !IsArmed() && throwType == THROW_PRIME )
+ {
+ SetArmed( true );
+
+ m_flDetonateTime = gpGlobals->curtime + GetDetonateTimerLength();
+
+ // start the hissing noise
+ }
+
+ m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+ m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
+ }
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ void CWeaponDODBaseGrenade::ItemPostFrame()
+ {
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+ if ( !pPlayer )
+ return;
+
+ CBaseViewModel *pViewModel = pPlayer->GetViewModel( m_nViewModelIndex );
+ if ( !pViewModel )
+ return;
+
+ if( IsArmed() && gpGlobals->curtime > m_flDetonateTime )
+ {
+ //Drop it!
+ DropGrenade();
+ m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
+ m_flNextSecondaryAttack = gpGlobals->curtime + 1.0;
+ return;
+ }
+
+ if ( m_bPinPulled &&
+ !(pPlayer->m_nButtons & IN_ATTACK) &&
+ !(pPlayer->m_nButtons & IN_ATTACK2) // If they let go of the fire button, they want to throw the grenade.
+ )
+ {
+ pPlayer->DoAnimationEvent( PLAYERANIMEVENT_THROW_GRENADE );
+
+ ThrowGrenade(false);
+
+ m_bRedraw = true;
+ m_bPinPulled = false;
+ SetArmed( false );
+
+ DecrementAmmo( pPlayer );
+
+ SendWeaponAnim( ACT_VM_THROW );
+ }
+ else
+ {
+ BaseClass::ItemPostFrame();
+
+ if ( m_bRedraw )
+ {
+ if (pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
+ {
+ pPlayer->Weapon_Drop( this, NULL, NULL );
+ UTIL_Remove(this);
+ }
+ else
+ Reload();
+ }
+ }
+ }
+
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ // Input : *pOwner -
+ //-----------------------------------------------------------------------------
+ void CWeaponDODBaseGrenade::DecrementAmmo( CBaseCombatCharacter *pOwner )
+ {
+ pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
+
+ if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
+ {
+ pOwner->Weapon_Drop( this, NULL, NULL );
+ UTIL_Remove(this);
+ }
+ }
+
+ void CWeaponDODBaseGrenade::DropGrenade( void )
+ {
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+ if ( !pPlayer )
+ return;
+
+ pPlayer->DoAnimationEvent( PLAYERANIMEVENT_THROW_GRENADE );
+
+ bool bThrow = true;
+
+ DODRoundState state = DODGameRules()->State_Get();
+
+ // If the player is holding a nade that is going to explode
+ // and the round is over, not allowing them to throw it
+ // just don't emit a grenade.
+ if ( dod_bonusround.GetBool() )
+ {
+ int team = pPlayer->GetTeamNumber();
+
+ if ( ( team == TEAM_ALLIES && state == STATE_AXIS_WIN ) ||
+ ( team == TEAM_AXIS && state == STATE_ALLIES_WIN ) )
+ {
+ bThrow = false;
+ }
+ }
+
+ if ( bThrow )
+ ThrowGrenade(true);
+
+ m_bRedraw = true;
+ m_bPinPulled = false;
+ SetArmed( false );
+
+ DecrementAmmo( pPlayer );
+
+ SendWeaponAnim( ACT_VM_THROW );
+ }
+
+ ConVar dod_grenadespeed( "dod_grenadespeed", "4.2", FCVAR_CHEAT );
+ ConVar dod_grenademaxspeed( "dod_grenademaxspeed", "1400", FCVAR_CHEAT );
+ ConVar dod_grenademinspeed( "dod_grenademinspeed", "500", FCVAR_CHEAT );
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ void CWeaponDODBaseGrenade::ThrowGrenade( bool bDrop )
+ {
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+ if ( !pPlayer )
+ {
+ Assert( false );
+ return;
+ }
+
+ QAngle angThrow = pPlayer->LocalEyeAngles();
+
+ Vector vForward, vRight, vUp;
+
+ if( angThrow.x > 180 )
+ angThrow.x -= 360;
+
+ if (angThrow.x < 0)
+ angThrow.x = -10 + angThrow.x * ((90 - 10) / 90.0);
+ else
+ angThrow.x = -10 + angThrow.x * ((90 + 10) / 90.0);
+
+ AngleVectors( angThrow, &vForward, &vRight, &vUp );
+
+ Vector eyes = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset();
+ Vector vecSrc = eyes + vForward * 16;
+
+ // Start with the player's velocity as the grenade vel
+ Vector vecPlayerVel;
+ pPlayer->GetVelocity( &vecPlayerVel, NULL );
+
+ // Get player angles, not eye angles!
+ QAngle angPlayerAngles = pPlayer->GetAbsAngles();
+ Vector vecPlayerForward;
+ AngleVectors( angPlayerAngles, &vecPlayerForward );
+ Vector vecThrow = DotProduct( vecPlayerVel, vecPlayerForward ) * vecPlayerForward;
+
+ if( bDrop )
+ {
+ vecThrow = vForward;
+ }
+ else // we are throwing the grenade
+ {
+ // change the speed depending on the throw angle
+ // straight down is 0%, straight up is 100%, linear between
+ float flSpeed = ( 90 - angThrow.x ) * dod_grenadespeed.GetFloat();
+
+ //Msg( "speed %.f\n", flSpeed );
+
+ flSpeed = clamp( flSpeed, dod_grenademinspeed.GetFloat(), dod_grenademaxspeed.GetFloat() );
+
+ vecThrow += vForward * flSpeed;
+ }
+
+ trace_t tr;
+ UTIL_TraceLine( eyes, vecSrc, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
+
+ // don't go into the ground
+ if( tr.fraction < 1.0 )
+ {
+ vecSrc = tr.endpos;
+ }
+
+ float flTimeLeft;
+
+ if ( IsArmed() )
+ flTimeLeft = MAX( 0, m_flDetonateTime - gpGlobals->curtime );
+ else
+ flTimeLeft = GetDetonateTimerLength();
+
+ EmitGrenade( vecSrc, vec3_angle, vecThrow, AngularImpulse(600,random->RandomInt(-1200,1200),0), pPlayer, flTimeLeft );
+
+ pPlayer->EmitSound( "Weapon_Grenade.Throw" );
+
+#ifndef CLIENT_DLL
+ IGameEvent * event = gameeventmanager->CreateEvent( "dod_stats_weapon_attack" );
+ if ( event )
+ {
+ event->SetInt( "attacker", pPlayer->GetUserID() );
+ event->SetInt( "weapon", GetStatsWeaponID() );
+
+ gameeventmanager->FireEvent( event );
+ }
+#endif //CLIENT_DLL
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ void CWeaponDODBaseGrenade::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime /* = GRENADE_FUSE_LENGTH */ )
+ {
+ Assert( 0 && "CBaseCSGrenade::EmitGrenade should not be called. Make sure to implement this in your subclass!\n" );
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ bool CWeaponDODBaseGrenade::AllowsAutoSwitchFrom( void ) const
+ {
+ return ( m_bPinPulled == false );
+ }
+
+ void CWeaponDODBaseGrenade::InputSetDetonateTime( inputdata_t &inputdata )
+ {
+ SetDetonateTime( inputdata.value.Float() );
+ }
+
+#endif // !CLIENT_DLL
+
+Activity CWeaponDODBaseGrenade::GetIdleActivity( void )
+{
+ if ( IsArmed() )
+ return ACT_VM_IDLE_EMPTY;
+ else
+ return ACT_VM_IDLE;
+}
+
+Activity CWeaponDODBaseGrenade::GetPrimaryAttackActivity( void )
+{
+ if ( IsArmed() )
+ return ACT_VM_PRIMARYATTACK_EMPTY;
+ else
+ return ACT_VM_PULLPIN;
+}
+
+Activity CWeaponDODBaseGrenade::GetDrawActivity( void )
+{
+ if ( IsArmed() )
+ return ACT_VM_DRAW_EMPTY;
+ else
+ return ACT_VM_DRAW;
+}
+
diff --git a/game/shared/dod/weapon_dodbasegrenade.h b/game/shared/dod/weapon_dodbasegrenade.h
new file mode 100644
index 0000000..9662fb3
--- /dev/null
+++ b/game/shared/dod/weapon_dodbasegrenade.h
@@ -0,0 +1,90 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WEAPON_DODBASEGRENADE_H
+#define WEAPON_DODBASEGRENADE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "weapon_dodbase.h"
+#include "dod_shareddefs.h"
+
+
+#ifdef CLIENT_DLL
+
+ #define CWeaponDODBaseGrenade C_WeaponDODBaseGrenade
+
+#endif
+
+
+class CWeaponDODBaseGrenade : public CWeaponDODBase
+{
+public:
+ DECLARE_CLASS( CWeaponDODBaseGrenade, CWeaponDODBase );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponDODBaseGrenade();
+
+ virtual void PrimaryAttack();
+ virtual bool CanHolster();
+
+ virtual bool IsArmed( void ) { return m_bArmed == true; }
+ void SetArmed( bool bArmed ) { m_bArmed = bArmed; }
+
+ virtual Activity GetIdleActivity( void );
+ virtual Activity GetPrimaryAttackActivity( void );
+ virtual Activity GetDrawActivity( void );
+
+#ifdef CLIENT_DLL
+
+#else
+ DECLARE_DATADESC();
+
+ virtual void Precache();
+ virtual void ItemPostFrame();
+ virtual bool AllowsAutoSwitchFrom( void ) const;
+ virtual bool Deploy();
+ virtual bool Holster( CBaseCombatWeapon *pSwitchingTo );
+ virtual bool Reload();
+
+ void DecrementAmmo( CBaseCombatCharacter *pOwner );
+
+ void StartThrow( int iThrowType );
+
+ void DropGrenade( void ); //forces the grenade to be dropped
+
+ virtual void ThrowGrenade( bool bDrop );
+
+ // Each derived grenade class implements this.
+ virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime = GRENADE_FUSE_LENGTH );
+
+ void SetDetonateTime( float flDetonateTime )
+ {
+ m_flDetonateTime = flDetonateTime;
+ SetArmed( true );
+ }
+
+ void InputSetDetonateTime( inputdata_t &inputdata );
+
+ virtual float GetDetonateTimerLength( void ) { return GRENADE_FUSE_LENGTH; }
+
+protected:
+
+#endif
+
+ bool m_bRedraw; // Draw the weapon again after throwing a grenade
+ CNetworkVar( bool, m_bPinPulled ); // Set to true when the pin has been pulled but the grenade hasn't been thrown yet.
+ CNetworkVar( bool, m_bArmed ); // is the grenade armed?
+ float m_flDetonateTime; // what time the grenade will explode ( if > 0 )
+ CWeaponDODBaseGrenade( const CWeaponDODBaseGrenade & ) {}
+};
+
+
+#endif // WEAPON_DODBASEGRENADE_H
diff --git a/game/shared/dod/weapon_dodbasegun.cpp b/game/shared/dod/weapon_dodbasegun.cpp
new file mode 100644
index 0000000..93fc0df
--- /dev/null
+++ b/game/shared/dod/weapon_dodbasegun.cpp
@@ -0,0 +1,252 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasegun.h"
+#include "fx_dod_shared.h"
+//#include "effect_dispatch_data.h"
+
+#ifdef CLIENT_DLL
+ #include "c_dod_player.h"
+ #include "prediction.h"
+#else
+ #include "dod_player.h"
+ #include "te_effect_dispatch.h"
+ #include "util.h"
+ #include "ndebugoverlay.h"
+#endif
+
+#ifndef CLIENT_DLL
+//-----------------------------------------------------------------------------
+// Purpose: Only send to local player if this weapon is the active weapon
+// Input : *pStruct -
+// *pVarData -
+// *pRecipients -
+// objectID -
+// Output : void*
+//-----------------------------------------------------------------------------
+void* SendProxy_SendActiveLocalBaseGunDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
+{
+ // Get the weapon entity
+ CBaseCombatWeapon *pWeapon = (CBaseCombatWeapon*)pVarData;
+ if ( pWeapon )
+ {
+ // Only send this chunk of data to the player carrying this weapon
+ CBasePlayer *pPlayer = ToBasePlayer( pWeapon->GetOwner() );
+ if ( pPlayer )
+ {
+ pRecipients->SetOnly( pPlayer->GetClientIndex() );
+ return (void*)pVarData;
+ }
+ }
+
+ return NULL;
+}
+REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendActiveLocalBaseGunDataTable );
+#endif
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponDODBaseGun, DT_WeaponDODBaseGun )
+
+BEGIN_NETWORK_TABLE_NOBASE( CWeaponDODBaseGun, DT_LocalActiveWeaponBaseGunData )
+END_NETWORK_TABLE()
+
+BEGIN_NETWORK_TABLE( CWeaponDODBaseGun, DT_WeaponDODBaseGun )
+ #ifdef CLIENT_DLL
+ RecvPropDataTable("LocalActiveWeaponBaseGunData", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalActiveWeaponBaseGunData))
+ #else
+ SendPropDataTable("LocalActiveWeaponBaseGunData", 0, &REFERENCE_SEND_TABLE(DT_LocalActiveWeaponBaseGunData), SendProxy_SendActiveLocalBaseGunDataTable )
+ #endif
+END_NETWORK_TABLE()
+
+#ifdef CLIENT_DLL
+
+ BEGIN_PREDICTION_DATA( CWeaponDODBaseGun )
+ END_PREDICTION_DATA()
+
+#else
+
+ BEGIN_DATADESC( CWeaponDODBaseGun )
+ END_DATADESC()
+
+#endif
+
+LINK_ENTITY_TO_CLASS( weapon_dod_base_gun, CWeaponDODBaseGun );
+
+extern ConVar friendlyfire;
+
+CWeaponDODBaseGun::CWeaponDODBaseGun()
+{
+}
+
+
+void CWeaponDODBaseGun::Spawn()
+{
+ DODBaseGunSpawn();
+
+ SetZoomed( false );
+}
+
+void CWeaponDODBaseGun::Precache()
+{
+ BaseClass::Precache();
+
+ // Precache all weapon ejections, since every weapon will appear in the game.
+ PrecacheModel( "models/shells/shell_small.mdl" );
+ PrecacheModel( "models/shells/shell_medium.mdl" );
+ PrecacheModel( "models/shells/shell_large.mdl" );
+ PrecacheModel( "models/shells/garand_clip.mdl" );
+}
+
+void CWeaponDODBaseGun::PrimaryAttack()
+{
+ Assert( m_pWeaponInfo );
+
+ DODBaseGunFire();
+}
+
+void CWeaponDODBaseGun::DODBaseGunSpawn( void )
+{
+ WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( GetClassname() );
+
+ Assert( hWpnInfo != GetInvalidWeaponInfoHandle() );
+
+ CDODWeaponInfo *pWeaponInfo = dynamic_cast< CDODWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
+
+ Assert( pWeaponInfo && "Failed to get CDODWeaponInfo in weapon spawn" );
+
+ m_pWeaponInfo = pWeaponInfo;
+
+ BaseClass::Spawn();
+}
+
+float CWeaponDODBaseGun::GetWeaponAccuracy( float flPlayerSpeed )
+{
+ //snipers and deployable weapons inherit this and override when we need a different accuracy
+
+ float flSpread = m_pWeaponInfo->m_flAccuracy;
+
+ if( flPlayerSpeed > 45 )
+ flSpread += m_pWeaponInfo->m_flAccuracyMovePenalty;
+
+ return flSpread;
+}
+
+bool CWeaponDODBaseGun::DODBaseGunFire()
+{
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+ Assert( pPlayer );
+
+ // Out of ammo?
+ if ( m_iClip1 <= 0 )
+ {
+ if (m_bFireOnEmpty)
+ {
+ PlayEmptySound();
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
+ }
+
+ return false;
+ }
+
+ if( pPlayer->GetWaterLevel() > 2 )
+ {
+ PlayEmptySound();
+ m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
+ return false;
+ }
+
+ /* decrement before calling PlayPrimaryAttackAnim, so we can play the empty anim if necessary */
+ m_iClip1--;
+
+ SendWeaponAnim( GetPrimaryAttackActivity() );
+
+ // player "shoot" animation
+ pPlayer->SetAnimation( PLAYER_ATTACK1 );
+
+ FX_FireBullets(
+ pPlayer->entindex(),
+ pPlayer->Weapon_ShootPosition(),
+ pPlayer->EyeAngles() + pPlayer->GetPunchAngle(),
+ GetWeaponID(),
+ Primary_Mode,
+ CBaseEntity::GetPredictionRandomSeed() & 255,
+ GetWeaponAccuracy( pPlayer->GetAbsVelocity().Length2D() ) );
+
+ DoFireEffects();
+
+#ifndef CLIENT_DLL
+ IGameEvent * event = gameeventmanager->CreateEvent( "dod_stats_weapon_attack" );
+ if ( event )
+ {
+ event->SetInt( "attacker", pPlayer->GetUserID() );
+ event->SetInt( "weapon", GetStatsWeaponID() );
+
+ gameeventmanager->FireEvent( event );
+ }
+#endif //CLIENT_DLL
+
+#ifdef CLIENT_DLL
+ CDODPlayer *p = ToDODPlayer( GetPlayerOwner() );
+
+ if ( prediction->IsFirstTimePredicted() )
+ p->DoRecoil( GetWeaponID(), GetRecoil() );
+#endif
+
+ m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + GetFireDelay();
+
+ m_flTimeWeaponIdle = gpGlobals->curtime + m_pWeaponInfo->m_flTimeToIdleAfterFire;
+ return true;
+}
+
+float CWeaponDODBaseGun::GetFireDelay( void )
+{
+ return m_pWeaponInfo->m_flFireDelay;
+}
+
+void CWeaponDODBaseGun::DoFireEffects()
+{
+ CBasePlayer *pPlayer = GetPlayerOwner();
+
+ if ( pPlayer )
+ pPlayer->DoMuzzleFlash();
+}
+
+
+bool CWeaponDODBaseGun::Reload()
+{
+ CBasePlayer *pPlayer = GetPlayerOwner();
+
+ if (pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0 && m_iClip1 <= 0 )
+ {
+ CDODPlayer *pDODPlayer = ToDODPlayer( pPlayer );
+ pDODPlayer->HintMessage( HINT_AMMO_EXHAUSTED );
+ return false;
+ }
+
+ int iResult = DefaultReload( GetMaxClip1(), GetMaxClip2(), GetReloadActivity() );
+ if ( !iResult )
+ return false;
+
+ pPlayer->SetAnimation( PLAYER_RELOAD );
+
+ return true;
+}
+
+Activity CWeaponDODBaseGun::GetPrimaryAttackActivity( void )
+{
+ return ACT_VM_PRIMARYATTACK;
+}
+
+Activity CWeaponDODBaseGun::GetReloadActivity( void )
+{
+ return ACT_VM_RELOAD;
+}
+
+Activity CWeaponDODBaseGun::GetDrawActivity( void )
+{
+ return ACT_VM_DRAW;
+}
diff --git a/game/shared/dod/weapon_dodbasegun.h b/game/shared/dod/weapon_dodbasegun.h
new file mode 100644
index 0000000..8ff215d
--- /dev/null
+++ b/game/shared/dod/weapon_dodbasegun.h
@@ -0,0 +1,83 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WEAPON_DODBASE_GUN_H
+#define WEAPON_DODBASE_GUN_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "weapon_dodbase.h"
+
+// This is the base class for pistols and rifles.
+#if defined( CLIENT_DLL )
+
+ //#include "particles_simple.h"
+ //#include "particles_localspace.h"
+ #include "fx.h"
+ #include "fx_dod_muzzleflash.h"
+
+ #define CWeaponDODBaseGun C_WeaponDODBaseGun
+
+#else
+#endif
+
+class CWeaponDODBaseGun : public CWeaponDODBase
+{
+public:
+
+ DECLARE_CLASS( CWeaponDODBaseGun, CWeaponDODBase );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CWeaponDODBaseGun();
+
+ virtual void Spawn();
+ virtual void Precache();
+ virtual void PrimaryAttack();
+ virtual bool Reload();
+
+ // Derived classes must call this from inside their Spawn() function instead of
+ // just chaining the Spawn() call down.
+ void DODBaseGunSpawn( void );
+
+ // Derived classes call this to fire a bullet.
+ bool DODBaseGunFire( void );
+
+ // Usually plays the shot sound. Guns with silencers can play different sounds.
+ virtual void DoFireEffects();
+ virtual float GetFireDelay( void );
+
+ virtual float GetWeaponAccuracy( float flPlayerSpeed );
+
+ //Pure animation calls - inheriting classes can override with specific
+ //logic, eg if the idle changes depending on the gun being empty or not
+ virtual Activity GetPrimaryAttackActivity( void );
+ virtual Activity GetReloadActivity( void );
+ virtual Activity GetDrawActivity( void );
+
+ virtual bool CanDrop( void ) { return m_pWeaponInfo->m_bCanDrop; }
+
+ void SetZoomed( bool bZoomed ) { m_bZoomed = bZoomed; }
+ bool IsSniperZoomed( void ) { return m_bZoomed; }
+ CNetworkVar( bool, m_bZoomed );
+
+protected:
+ CDODWeaponInfo *m_pWeaponInfo;
+
+private:
+ CWeaponDODBaseGun( const CWeaponDODBaseGun & );
+
+#ifndef CLIENT_DLL
+
+ DECLARE_DATADESC();
+
+#endif
+};
+
+
+#endif // WEAPON_DODBASE_GUN_H
diff --git a/game/shared/dod/weapon_dodbasemelee.cpp b/game/shared/dod/weapon_dodbasemelee.cpp
new file mode 100644
index 0000000..066bbfc
--- /dev/null
+++ b/game/shared/dod/weapon_dodbasemelee.cpp
@@ -0,0 +1,237 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasemelee.h"
+#include "dod_gamerules.h"
+
+#if defined( CLIENT_DLL )
+ #include "c_dod_player.h"
+#else
+ #include "dod_player.h"
+ #include "ilagcompensationmanager.h"
+#endif
+
+#include "effect_dispatch_data.h"
+
+
+#define KNIFE_BODYHIT_VOLUME 128
+#define KNIFE_WALLHIT_VOLUME 512
+
+// ----------------------------------------------------------------------------- //
+// CWeaponDODBaseMelee tables.
+// ----------------------------------------------------------------------------- //
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponDODBaseMelee, DT_WeaponDODBaseMelee )
+
+BEGIN_NETWORK_TABLE_NOBASE( CWeaponDODBaseMelee, DT_LocalActiveWeaponBaseMeleeData )
+END_NETWORK_TABLE()
+
+BEGIN_NETWORK_TABLE( CWeaponDODBaseMelee, DT_WeaponDODBaseMelee )
+END_NETWORK_TABLE()
+
+#ifdef CLIENT_DLL
+BEGIN_PREDICTION_DATA( CWeaponDODBaseMelee )
+ DEFINE_PRED_FIELD( m_flSmackTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
+END_PREDICTION_DATA()
+#endif
+
+LINK_ENTITY_TO_CLASS( weapon_dod_base_melee, CWeaponDODBaseMelee );
+
+#ifndef CLIENT_DLL
+
+ BEGIN_DATADESC( CWeaponDODBaseMelee )
+ DEFINE_FUNCTION( Smack )
+ END_DATADESC()
+
+#endif
+
+// ----------------------------------------------------------------------------- //
+// CWeaponDODBaseMelee implementation.
+// ----------------------------------------------------------------------------- //
+
+CWeaponDODBaseMelee::CWeaponDODBaseMelee()
+{
+}
+
+void CWeaponDODBaseMelee::Spawn()
+{
+ Precache();
+
+ WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( GetClassname() );
+
+ Assert( hWpnInfo != GetInvalidWeaponInfoHandle() );
+
+ CDODWeaponInfo *pWeaponInfo = dynamic_cast< CDODWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
+
+ Assert( pWeaponInfo && "Failed to get CDODWeaponInfo in melee weapon spawn" );
+
+ m_pWeaponInfo = pWeaponInfo;
+
+ Assert( m_pWeaponInfo );
+
+ m_iClip1 = -1;
+ BaseClass::Spawn();
+}
+
+void CWeaponDODBaseMelee::WeaponIdle( void )
+{
+ if ( m_flTimeWeaponIdle > gpGlobals->curtime )
+ return;
+
+ SendWeaponAnim( ACT_VM_IDLE );
+
+ m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
+}
+
+void CWeaponDODBaseMelee::PrimaryAttack()
+{
+ MeleeAttack( 60, MELEE_DMG_EDGE, 0.2f, 0.4f );
+}
+
+CBaseEntity *CWeaponDODBaseMelee::MeleeAttack( int iDamageAmount, int iDamageType, float flDmgDelay, float flAttackDelay )
+{
+ if ( !CanAttack() )
+ return NULL;
+
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+#if !defined (CLIENT_DLL)
+ // Move other players back to history positions based on local player's lag
+ lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() );
+#endif
+
+ Vector vForward, vRight, vUp;
+ AngleVectors( pPlayer->EyeAngles(), &vForward, &vRight, &vUp );
+ Vector vecSrc = pPlayer->Weapon_ShootPosition();
+ Vector vecEnd = vecSrc + vForward * 48;
+
+ CTraceFilterSimple filter( pPlayer, COLLISION_GROUP_NONE );
+
+ int iTraceMask = MASK_SOLID | CONTENTS_HITBOX | CONTENTS_DEBRIS;
+
+ trace_t tr;
+ UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &filter, &tr );
+
+ const float rayExtension = 40.0f;
+ UTIL_ClipTraceToPlayers( vecSrc, vecEnd + vForward * rayExtension, iTraceMask, &filter, &tr );
+
+ if ( tr.fraction >= 1.0 )
+ {
+ Vector head_hull_mins( -16, -16, -18 );
+ Vector head_hull_maxs( 16, 16, 18 );
+
+ UTIL_TraceHull( vecSrc, vecEnd, head_hull_mins, head_hull_maxs, MASK_SOLID, &filter, &tr );
+ if ( tr.fraction < 1.0 )
+ {
+ // Calculate the point of intersection of the line (or hull) and the object we hit
+ // This is and approximation of the "best" intersection
+ CBaseEntity *pHit = tr.m_pEnt;
+ if ( !pHit || pHit->IsBSPModel() )
+ FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, pPlayer );
+ vecEnd = tr.endpos; // This is the point on the actual surface (the hull could have hit space)
+
+ // Make sure it is in front of us
+ Vector vecToEnd = vecEnd - vecSrc;
+ VectorNormalize( vecToEnd );
+
+ // if zero length, always hit
+ if ( vecToEnd.Length() > 0 )
+ {
+ float dot = DotProduct( vForward, vecToEnd );
+
+ // sanity that our hit is within range
+ if ( abs(dot) < 0.95 )
+ {
+ // fake that we actually missed
+ tr.fraction = 1.0;
+ }
+ }
+ }
+ }
+
+ bool bDidHit = ( tr.fraction < 1.0f );
+
+ bool bDoStrongAttack = false;
+
+ if ( bDidHit && tr.m_pEnt->IsPlayer() && tr.m_pEnt->m_takedamage != DAMAGE_YES )
+ {
+ bDidHit = 0; // still play the animation, we just dont attempt to damage this player
+ }
+
+ if ( bDidHit ) //if the swing hit
+ {
+ // delay the decal a bit
+ m_trHit = tr;
+
+ // Store the ent in an EHANDLE, just in case it goes away by the time we get into our think function.
+ m_pTraceHitEnt = tr.m_pEnt;
+
+ m_iSmackDamage = iDamageAmount;
+ m_iSmackDamageType = iDamageType;
+
+ m_flSmackTime = gpGlobals->curtime + flDmgDelay;
+
+ int iOwnerTeam = pPlayer->GetTeamNumber();
+ int iVictimTeam = tr.m_pEnt->GetTeamNumber();
+
+ // do the mega attack if its a player, and we would do damage
+ if ( tr.m_pEnt->IsPlayer() &&
+ tr.m_pEnt->m_takedamage == DAMAGE_YES &&
+ ( iVictimTeam != iOwnerTeam || ( iVictimTeam == iOwnerTeam && friendlyfire.GetBool() ) ) )
+ {
+ CDODPlayer *pVictim = ToDODPlayer( tr.m_pEnt );
+
+ Vector victimForward;
+ AngleVectors( pVictim->GetAbsAngles(), &victimForward );
+
+ if ( DotProduct( victimForward, vForward ) > 0.3 )
+ {
+ bDoStrongAttack = true;
+ }
+ }
+ }
+
+ if ( bDoStrongAttack )
+ {
+ m_iSmackDamage = 300;
+ flAttackDelay = 0.9f;
+ m_flSmackTime = gpGlobals->curtime + 0.4f;
+
+ m_iSmackDamageType = MELEE_DMG_EDGE | MELEE_DMG_STRONGATTACK;
+
+ // play a "Strong" attack
+ SendWeaponAnim( ACT_VM_SECONDARYATTACK );
+ }
+ else
+ {
+ WeaponSound( MELEE_MISS );
+ SendWeaponAnim( GetMeleeActivity() );
+ }
+
+ // player animation
+ pPlayer->DoAnimationEvent( PLAYERANIMEVENT_SECONDARY_ATTACK );
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + flAttackDelay;
+ m_flNextSecondaryAttack = gpGlobals->curtime + flAttackDelay;
+ m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
+
+
+#ifndef CLIENT_DLL
+ IGameEvent * event = gameeventmanager->CreateEvent( "dod_stats_weapon_attack" );
+ if ( event )
+ {
+ event->SetInt( "attacker", pPlayer->GetUserID() );
+ event->SetInt( "weapon", GetStatsWeaponID() );
+
+ gameeventmanager->FireEvent( event );
+ }
+
+ lagcompensation->FinishLagCompensation( pPlayer );
+#endif //CLIENT_DLL
+
+ return tr.m_pEnt;
+} \ No newline at end of file
diff --git a/game/shared/dod/weapon_dodbasemelee.h b/game/shared/dod/weapon_dodbasemelee.h
new file mode 100644
index 0000000..325f9f7
--- /dev/null
+++ b/game/shared/dod/weapon_dodbasemelee.h
@@ -0,0 +1,57 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WEAPON_DODBASE_MELEE_H
+#define WEAPON_DODBASE_MELEE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "weapon_dodbase.h"
+
+#if defined( CLIENT_DLL )
+ #define CWeaponDODBaseMelee C_WeaponDODBaseMelee
+#endif
+
+// ----------------------------------------------------------------------------- //
+// class definition.
+// ----------------------------------------------------------------------------- //
+
+class CWeaponDODBaseMelee : public CWeaponDODBase
+{
+public:
+ DECLARE_CLASS( CWeaponDODBaseMelee, CWeaponDODBase );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ #ifndef CLIENT_DLL
+ DECLARE_DATADESC();
+ #endif
+
+ CWeaponDODBaseMelee();
+
+ virtual void Spawn();
+ virtual void PrimaryAttack();
+ virtual void WeaponIdle();
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_NONE; }
+ virtual bool ShouldDrawCrosshair( void ) { return false; }
+ virtual bool HasPrimaryAmmo() { return true; }
+ virtual bool CanBeSelected() { return true; }
+
+ virtual CBaseEntity *MeleeAttack( int iDamageAmount, int iDamageType, float flDmgDelay, float flAttackDelay );
+
+ //virtual const char *GetSecondaryDeathNoticeName( void ) { return "stab"; }
+
+public:
+ CDODWeaponInfo *m_pWeaponInfo;
+
+private:
+ CWeaponDODBaseMelee( const CWeaponDODBaseMelee & ) {}
+};
+
+
+#endif // WEAPON_DODBASE_MELEE_H
diff --git a/game/shared/dod/weapon_dodbaserpg.cpp b/game/shared/dod/weapon_dodbaserpg.cpp
new file mode 100644
index 0000000..a9d196d
--- /dev/null
+++ b/game/shared/dod/weapon_dodbaserpg.cpp
@@ -0,0 +1,345 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "dod_gamerules.h"
+#include "weapon_dodbaserpg.h"
+
+
+#ifdef CLIENT_DLL
+
+ #include "c_dod_player.h"
+ #include "prediction.h"
+
+#else
+
+ #include "dod_player.h"
+
+#endif
+
+IMPLEMENT_NETWORKCLASS_ALIASED( DODBaseRocketWeapon, DT_BaseRocketWeapon )
+
+BEGIN_NETWORK_TABLE( CDODBaseRocketWeapon, DT_BaseRocketWeapon )
+
+#ifdef CLIENT_DLL
+ RecvPropBool( RECVINFO(m_bDeployed) )
+#else
+ SendPropBool( SENDINFO(m_bDeployed) )
+#endif
+
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CDODBaseRocketWeapon )
+END_PREDICTION_DATA()
+
+#ifndef CLIENT_DLL
+
+BEGIN_DATADESC( CDODBaseRocketWeapon )
+END_DATADESC()
+
+#endif
+
+LINK_ENTITY_TO_CLASS( weapon_dodbaserpg, CDODBaseRocketWeapon );
+
+CDODBaseRocketWeapon::CDODBaseRocketWeapon()
+{
+}
+
+void CDODBaseRocketWeapon::Precache()
+{
+ BaseClass::Precache();
+}
+
+bool CDODBaseRocketWeapon::Reload( void )
+{
+ CDODPlayer *pPlayer = GetDODPlayerOwner();
+
+ if (pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0)
+ {
+ CDODPlayer *pDODPlayer = ToDODPlayer( pPlayer );
+ pDODPlayer->HintMessage( HINT_AMMO_EXHAUSTED );
+ return false;
+ }
+
+ Activity actReload;
+
+ if( IsDeployed() )
+ actReload = ACT_VM_RELOAD_DEPLOYED;
+ else
+ actReload = ACT_VM_RELOAD;
+
+ int iResult = DefaultReload( GetMaxClip1(), GetMaxClip2(), actReload );
+ if ( !iResult )
+ return false;
+
+ pPlayer->SetAnimation( PLAYER_RELOAD );
+
+ // if we don't want the auto-rezoom, undeploy here
+ if ( !pPlayer->ShouldAutoRezoom() )
+ {
+ m_bDeployed = false;
+ pPlayer->SetBazookaDeployed( m_bDeployed );
+ }
+
+ return true;
+}
+
+bool CDODBaseRocketWeapon::ShouldPlayerBeSlow( void )
+{
+ if( IsDeployed() && !m_bInReload )
+ {
+ return true;
+ }
+ else
+ return false;
+}
+
+void CDODBaseRocketWeapon::Spawn( )
+{
+ WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( GetClassname() );
+
+ Assert( hWpnInfo != GetInvalidWeaponInfoHandle() );
+
+ CDODWeaponInfo *pWeaponInfo = dynamic_cast< CDODWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
+
+ Assert( pWeaponInfo && "Failed to get CDODWeaponInfo in weapon spawn" );
+
+ m_pWeaponInfo = pWeaponInfo;
+
+ BaseClass::Spawn();
+}
+
+void CDODBaseRocketWeapon::Drop( const Vector &vecVelocity )
+{
+ SetDeployed( false );
+
+ BaseClass::Drop( vecVelocity );
+}
+
+bool CDODBaseRocketWeapon::Deploy( )
+{
+ return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), GetDrawActivity(), (char*)GetAnimPrefix() );
+}
+
+Activity CDODBaseRocketWeapon::GetDrawActivity( void )
+{
+ return ACT_VM_DRAW;
+}
+
+bool CDODBaseRocketWeapon::CanHolster( void )
+{
+ // can't holster if we are delpoyed and not reloading
+ if ( IsDeployed() && !m_bInReload )
+ return false;
+
+ return true;
+}
+
+bool CDODBaseRocketWeapon::Holster( CBaseCombatWeapon *pSwitchingTo )
+{
+#ifndef CLIENT_DLL
+
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+ pPlayer->SetBazookaDeployed( false );
+
+#endif
+
+ SetDeployed( false );
+
+ return BaseClass::Holster(pSwitchingTo);
+}
+
+
+void CDODBaseRocketWeapon::PrimaryAttack()
+{
+ Assert( m_pWeaponInfo );
+
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+ // Out of ammo?
+ if ( m_iClip1 <= 0 )
+ {
+ if (m_bFireOnEmpty)
+ {
+ PlayEmptySound();
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
+ }
+
+ return;
+ }
+
+ if( pPlayer->GetWaterLevel() > 2 )
+ {
+ PlayEmptySound();
+ m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
+ return;
+ }
+
+ if( IsDeployed() )
+ {
+ // player "shoot" animation
+ pPlayer->SetAnimation( PLAYER_ATTACK1 );
+
+ SendWeaponAnim( ACT_VM_PRIMARYATTACK );
+
+ FireRocket();
+
+ DoFireEffects();
+
+ m_iClip1--;
+
+#ifdef CLIENT_DLL
+ if ( prediction->IsFirstTimePredicted() )
+ pPlayer->DoRecoil( GetWeaponID(), GetRecoil() );
+#endif
+
+ if ( m_iClip1 <= 0 && pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0 )
+ {
+ Lower();
+ }
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration() + 0.5;
+ m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration() + 0.5; //length of the fire anim!
+
+#ifndef CLIENT_DLL
+ IGameEvent * event = gameeventmanager->CreateEvent( "dod_stats_weapon_attack" );
+ if ( event )
+ {
+ event->SetInt( "attacker", pPlayer->GetUserID() );
+ event->SetInt( "weapon", GetStatsWeaponID() );
+
+ gameeventmanager->FireEvent( event );
+ }
+#endif //CLIENT_DLL
+ }
+ else
+ {
+#ifdef CLIENT_DLL
+ pPlayer->HintMessage( HINT_SHOULDER_WEAPON, true );
+#endif
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + 2.0f;
+ }
+}
+
+void CDODBaseRocketWeapon::FireRocket( void )
+{
+ Assert( !"Derived classes must implement this." );
+}
+
+void CDODBaseRocketWeapon::DoFireEffects()
+{
+ CBasePlayer *pPlayer = GetPlayerOwner();
+
+ if ( pPlayer )
+ pPlayer->DoMuzzleFlash();
+
+ //smoke etc
+}
+
+void CDODBaseRocketWeapon::SecondaryAttack()
+{
+ CBasePlayer *pPlayer = GetPlayerOwner();
+
+ //if we're underwater, lower it
+ if( pPlayer->GetWaterLevel() > 2 )
+ {
+ if( IsDeployed() )
+ Lower();
+ return;
+ }
+
+ if( IsDeployed() )
+ {
+ Lower();
+ }
+ else
+ {
+ if ( CanAttack() )
+ Raise();
+ }
+}
+
+void CDODBaseRocketWeapon::WeaponIdle()
+{
+ if (m_flTimeWeaponIdle > gpGlobals->curtime)
+ return;
+
+ SendWeaponAnim( GetIdleActivity() );
+
+ m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
+}
+
+Activity CDODBaseRocketWeapon::GetIdleActivity( void )
+{
+ Activity actIdle;
+
+ if( IsDeployed() )
+ actIdle = ACT_VM_IDLE_DEPLOYED;
+ else
+ actIdle = ACT_VM_IDLE;
+
+ return actIdle;
+}
+
+/* Raise the Bazooka to your shoulder */
+void CDODBaseRocketWeapon::Raise()
+{
+ //raise to the shoulder
+ SendWeaponAnim( GetRaiseActivity() );
+
+ m_bDeployed = true;
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+ m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
+ m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
+}
+
+/* Lower the bazooka to running position */
+bool CDODBaseRocketWeapon::Lower()
+{
+ SendWeaponAnim( GetLowerActivity() );
+
+ m_bDeployed = false;
+
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+ pPlayer->SetBazookaDeployed( m_bDeployed );
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+ m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
+ m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
+
+ return true;
+}
+
+Activity CDODBaseRocketWeapon::GetLowerActivity( void )
+{
+ return ACT_VM_UNDEPLOY;
+}
+
+Activity CDODBaseRocketWeapon::GetRaiseActivity( void )
+{
+ return ACT_VM_DEPLOY;
+}
+
+#ifdef CLIENT_DLL
+
+ConVar deployed_bazooka_sensitivity( "deployed_bazooka_sensitivity", "0.6", FCVAR_CHEAT, "Mouse sensitivity while deploying a bazooka" );
+
+void CDODBaseRocketWeapon::OverrideMouseInput( float *x, float *y )
+{
+ if( m_bDeployed )
+ {
+ float flSensitivity = deployed_bazooka_sensitivity.GetFloat();
+
+ *x *= flSensitivity;
+ *y *= flSensitivity;
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/game/shared/dod/weapon_dodbaserpg.h b/game/shared/dod/weapon_dodbaserpg.h
new file mode 100644
index 0000000..0b570c7
--- /dev/null
+++ b/game/shared/dod/weapon_dodbaserpg.h
@@ -0,0 +1,88 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef WEAPON_DODBASERPG_H
+#define WEAPON_DODBASERPG_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "weapon_dodbase.h"
+
+
+#if defined( CLIENT_DLL )
+
+ #define CDODBaseRocketWeapon C_DODBaseRocketWeapon
+
+#endif
+
+//-----------------------------------------------------------------------------
+// RPG
+//-----------------------------------------------------------------------------
+class CDODBaseRocketWeapon : public CWeaponDODBase
+{
+public:
+ DECLARE_CLASS( CDODBaseRocketWeapon, CWeaponDODBase );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CDODBaseRocketWeapon();
+
+ virtual void Spawn();
+ virtual void PrimaryAttack();
+ virtual void SecondaryAttack();
+ virtual bool Deploy();
+ virtual bool CanHolster();
+ virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
+ virtual bool Reload();
+ virtual void WeaponIdle();
+ virtual void Drop( const Vector &vecVelocity );
+
+ virtual bool CanDrop( void ) { return ( IsDeployed() == false ); }
+
+ void DoFireEffects();
+
+ void Precache( void );
+
+ void Raise();
+ bool Lower();
+
+ virtual Activity GetDrawActivity( void );
+ virtual Activity GetIdleActivity( void );
+ virtual Activity GetLowerActivity( void );
+ virtual Activity GetRaiseActivity( void );
+
+ virtual void FireRocket( void );
+
+ inline bool IsDeployed() { return m_bDeployed; }
+ inline void SetDeployed( bool bDeployed ) { m_bDeployed = bDeployed; }
+
+ bool ShouldPlayerBeSlow( void );
+
+ virtual bool ShouldAutoEjectBrass( void ) { return false; }
+
+#ifdef CLIENT_DLL
+ virtual void OverrideMouseInput( float *x, float *y );
+#endif
+
+ virtual float GetRecoil( void ) { return 10.0f; }
+
+protected:
+ CNetworkVar( bool, m_bDeployed );
+
+ CDODWeaponInfo *m_pWeaponInfo;
+
+private:
+ CDODBaseRocketWeapon( const CDODBaseRocketWeapon & );
+
+#ifndef CLIENT_DLL
+ DECLARE_DATADESC();
+#endif
+};
+
+#endif // WEAPON_DODBASERPG_H \ No newline at end of file
diff --git a/game/shared/dod/weapon_dodbipodgun.cpp b/game/shared/dod/weapon_dodbipodgun.cpp
new file mode 100644
index 0000000..09b0d40
--- /dev/null
+++ b/game/shared/dod/weapon_dodbipodgun.cpp
@@ -0,0 +1,782 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "fx_dod_shared.h"
+#include "weapon_dodbipodgun.h"
+#include "dod_gamerules.h"
+#include "engine/IEngineSound.h"
+
+#ifndef CLIENT_DLL
+#include "ndebugoverlay.h"
+#endif
+
+IMPLEMENT_NETWORKCLASS_ALIASED( DODBipodWeapon, DT_BipodWeapon )
+
+BEGIN_NETWORK_TABLE( CDODBipodWeapon, DT_BipodWeapon )
+#ifdef CLIENT_DLL
+ RecvPropBool( RECVINFO( m_bDeployed ) ),
+ RecvPropInt( RECVINFO( m_iDeployedReloadModelIndex) ),
+#else
+ SendPropBool( SENDINFO( m_bDeployed ) ),
+ SendPropModelIndex( SENDINFO(m_iDeployedReloadModelIndex) ),
+#endif
+END_NETWORK_TABLE()
+
+#ifdef CLIENT_DLL
+BEGIN_PREDICTION_DATA( CDODBipodWeapon )
+ DEFINE_PRED_FIELD( m_bDeployed, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE )
+END_PREDICTION_DATA()
+#endif
+
+CDODBipodWeapon::CDODBipodWeapon()
+{
+}
+
+void CDODBipodWeapon::Spawn()
+{
+ SetDeployed( false );
+ m_flNextDeployCheckTime = 0;
+
+ m_iCurrentWorldModel = 0;
+
+ m_iAltFireHint = HINT_USE_DEPLOY;
+
+ BaseClass::Spawn();
+}
+
+void CDODBipodWeapon::SetDeployed( bool bDeployed )
+{
+ if ( bDeployed == false )
+ {
+ m_hDeployedOnEnt = NULL;
+ m_DeployedEntOrigin = vec3_origin;
+ m_flDeployedHeight = 0;
+
+#ifdef GAME_DLL
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+ if ( pPlayer )
+ {
+ pPlayer->HandleDeployedMGKillCount( 0 ); // reset when we undeploy
+ }
+#endif
+ }
+
+ m_bDeployed = bDeployed;
+}
+
+void CDODBipodWeapon::Precache( void )
+{
+ // precache base first, it loads weapon scripts
+ BaseClass::Precache();
+
+ const CDODWeaponInfo &info = GetDODWpnData();
+
+ if( Q_strlen(info.m_szDeployedModel) > 0 )
+ {
+ Assert( info.m_iAltWpnCriteria & ALTWPN_CRITERIA_DEPLOYED );
+ m_iDeployedModelIndex = CBaseEntity::PrecacheModel( info.m_szDeployedModel );
+ }
+
+ if( Q_strlen(info.m_szDeployedReloadModel) > 0 )
+ {
+ Assert( info.m_iAltWpnCriteria & ALTWPN_CRITERIA_DEPLOYED_RELOAD );
+ m_iDeployedReloadModelIndex = CBaseEntity::PrecacheModel( info.m_szDeployedReloadModel );
+ }
+
+ if( Q_strlen(info.m_szProneDeployedReloadModel) > 0 )
+ {
+ Assert( info.m_iAltWpnCriteria & ALTWPN_CRITERIA_PRONE_DEPLOYED_RELOAD );
+ m_iProneDeployedReloadModelIndex = CBaseEntity::PrecacheModel( info.m_szProneDeployedReloadModel );
+ }
+
+ m_iCurrentWorldModel = m_iWorldModelIndex;
+ Assert( m_iCurrentWorldModel != 0 );
+}
+
+bool CDODBipodWeapon::CanDrop( void )
+{
+ return ( IsDeployed() == false );
+}
+
+bool CDODBipodWeapon::CanHolster( void )
+{
+ return ( IsDeployed() == false );
+}
+
+void CDODBipodWeapon::Drop( const Vector &vecVelocity )
+{
+ // If a player is killed while deployed, this resets the weapon state
+ SetDeployed( false );
+
+ BaseClass::Drop( vecVelocity );
+}
+
+void CDODBipodWeapon::SecondaryAttack( void )
+{
+ // Toggle deployed / undeployed
+
+ if ( IsDeployed() )
+ UndeployBipod();
+ else
+ {
+ if ( CanAttack() )
+ {
+ bool bSuccess = AttemptToDeploy();
+
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+ Assert( pPlayer );
+
+ if ( !bSuccess )
+ {
+ pPlayer->HintMessage( HINT_MG_DEPLOY_USAGE );
+ }
+ else
+ {
+#ifndef CLIENT_DLL
+ pPlayer->RemoveHintTimer( m_iAltFireHint );
+#endif
+ }
+ }
+ }
+}
+
+bool CDODBipodWeapon::Reload( void )
+{
+ bool bSuccess = BaseClass::Reload();
+
+ if ( bSuccess )
+ {
+ m_flNextSecondaryAttack = gpGlobals->curtime;
+ }
+
+ return bSuccess;
+}
+
+#include "in_buttons.h"
+// check in busy frame too, to catch cancelling reloads
+void CDODBipodWeapon::ItemBusyFrame( void )
+{
+ BipodThink();
+
+ CBasePlayer *pPlayer = GetPlayerOwner();
+
+ if ( !pPlayer )
+ return;
+
+ if ((pPlayer->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime))
+ {
+ SecondaryAttack();
+
+ pPlayer->m_nButtons &= ~IN_ATTACK2;
+ }
+
+ BaseClass::ItemBusyFrame();
+}
+
+void CDODBipodWeapon::ItemPostFrame( void )
+{
+ BipodThink();
+ BaseClass::ItemPostFrame();
+}
+
+// see if we're still deployed on the same entity at the same height
+// in future can be expanded to check when deploying on other ents that may move / die / break
+void CDODBipodWeapon::BipodThink( void )
+{
+ if ( m_flNextDeployCheckTime < gpGlobals->curtime )
+ {
+ if ( IsDeployed() )
+ {
+ if ( CheckDeployEnt() == false )
+ {
+ UndeployBipod();
+
+ // cancel any reload in progress
+ m_bInReload = false;
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.1;
+ m_flNextSecondaryAttack = gpGlobals->curtime + 0.1;
+ }
+ }
+
+ m_flNextDeployCheckTime = gpGlobals->curtime + 0.2;
+ }
+}
+
+void CDODBipodWeapon::DoFireEffects()
+{
+ BaseClass::DoFireEffects();
+
+ CBaseEntity *pDeployedOn = m_hDeployedOnEnt.Get();
+
+ // in future can be expanded to check when deploying on other ents that may move / die / break
+ if ( pDeployedOn && pDeployedOn->IsPlayer() && IsDeployed() )
+ {
+#ifndef CLIENT_DLL
+ CSingleUserRecipientFilter user( (CBasePlayer *)pDeployedOn );
+ enginesound->SetPlayerDSP( user, 32, false );
+#endif
+ }
+}
+
+// Do the work of deploying the gun at the current location and angles
+void CDODBipodWeapon::DeployBipod( float flHeight, CBaseEntity *pDeployedOn, float flYawLimitLeft, float flYawLimitRight )
+{
+ m_flDeployedHeight = flHeight;
+ m_hDeployedOnEnt = pDeployedOn;
+
+ if ( pDeployedOn )
+ m_DeployedEntOrigin = pDeployedOn->GetAbsOrigin();
+ else
+ m_DeployedEntOrigin = vec3_origin; // world ent
+
+ SendWeaponAnim( GetDeployActivity() );
+ SetDeployed( true );
+
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+ pPlayer->m_Shared.SetDeployed( true, flHeight );
+ pPlayer->m_Shared.SetDeployedYawLimits( flYawLimitLeft, flYawLimitRight );
+
+ // Save this off so we do duck checks later, even though we won't be flagged as ducking
+ m_bDuckedWhenDeployed = pPlayer->m_Shared.IsDucking();
+
+ // More TODO:
+ // recalc our yaw limits if the item we're deployed on has moved or rotated
+ // if our new limits are outside our current eye angles, undeploy us
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+ m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
+ m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
+}
+
+// Do the work of undeploying the gun
+void CDODBipodWeapon::UndeployBipod( void )
+{
+ SendWeaponAnim( GetUndeployActivity() );
+ SetDeployed( false );
+
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+ pPlayer->m_Shared.SetDeployed( false );
+
+ // if we cancelled our reload by undeploying, don't let the reload complete
+ if ( m_bInReload )
+ m_bInReload = false;
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+ m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
+ pPlayer->m_flNextAttack = m_flNextPrimaryAttack;
+ m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
+}
+
+#ifndef CLIENT_DLL
+ConVar dod_debugmgdeploy( "dod_debugmgdeploy", "0", FCVAR_CHEAT|FCVAR_GAMEDLL );
+#endif
+
+bool CDODBipodWeapon::AttemptToDeploy( void )
+{
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+ if ( pPlayer->GetGroundEntity() == NULL )
+ return false;
+
+ if ( pPlayer->m_Shared.IsGettingUpFromProne() || pPlayer->m_Shared.IsGoingProne() )
+ return false;
+
+ CBaseEntity *pDeployedOn = NULL;
+ float flDeployedHeight = 0.0f;
+ float flYawLimitLeft = 0;
+ float flYawLimitRight = 0;
+
+ if ( TestDeploy( &flDeployedHeight, &pDeployedOn, &flYawLimitLeft, &flYawLimitRight ) )
+ {
+ if ( pPlayer->m_Shared.IsProne() && !pPlayer->m_Shared.IsGettingUpFromProne() )
+ {
+ DeployBipod( flDeployedHeight, NULL, flYawLimitLeft, flYawLimitRight );
+ return true;
+ }
+ else
+ {
+ float flMinDeployHeight = 24.0;
+ if( flDeployedHeight >= flMinDeployHeight )
+ {
+ DeployBipod( flDeployedHeight, pDeployedOn, flYawLimitLeft, flYawLimitRight );
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool CDODBipodWeapon::CheckDeployEnt( void )
+{
+ CBaseEntity *pDeployedOn = NULL;
+ float flDeployedHeight = 0.0f;
+
+ if ( TestDeploy( &flDeployedHeight, &pDeployedOn ) == false )
+ return false;
+
+ // If the entity we were deployed on has changed, or has moved, the origin
+ // of it will be different. If so, recalc our yaw limits.
+ if ( pDeployedOn )
+ {
+ if ( m_DeployedEntOrigin != pDeployedOn->GetAbsOrigin() )
+ {
+ float flYawLimitLeft = 0, flYawLimitRight = 0;
+ TestDeploy( &flDeployedHeight, &pDeployedOn, &flYawLimitLeft, &flYawLimitRight );
+
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+ if ( pPlayer )
+ pPlayer->m_Shared.SetDeployedYawLimits( flYawLimitLeft, flYawLimitRight );
+
+ m_DeployedEntOrigin = pDeployedOn->GetAbsOrigin();
+ }
+ }
+
+ // 20 unit tolerance in height
+ if ( abs( m_flDeployedHeight - flDeployedHeight ) > 20 )
+ return false;
+
+ return true;
+}
+
+bool CDODBipodWeapon::TestDeploy( float *flDeployedHeight, CBaseEntity **pDeployedOn, float *flYawLimitLeft /* = NULL */, float *flYawLimitRight /* = NULL */ )
+{
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+ QAngle angles = pPlayer->EyeAngles();
+
+ float flPitch = angles[PITCH];
+ if( flPitch > 180 )
+ {
+ flPitch -= 360;
+ }
+
+ if( flPitch > MIN_DEPLOY_PITCH || flPitch < MAX_DEPLOY_PITCH )
+ {
+ return false;
+ }
+
+ bool bSuccess = false;
+
+ // if we're not finding the range, test at the current angles
+ if ( flYawLimitLeft == NULL && flYawLimitRight == NULL )
+ {
+ // test our current angle only
+ bSuccess = TestDeployAngle( pPlayer, flDeployedHeight, pDeployedOn, angles );
+ }
+ else
+ {
+ float flSaveYaw = angles[YAW];
+
+ const float flAngleDelta = 5;
+ const float flMaxYaw = 45;
+
+ float flLeft = 0;
+ float flRight = 0;
+
+ float flTestDeployHeight = 0;
+ CBaseEntity *pTestDeployedOn = NULL;
+
+ // Sweep Left
+ while ( flLeft <= flMaxYaw )
+ {
+ angles[YAW] = flSaveYaw + flLeft;
+
+ if ( TestDeployAngle( pPlayer, &flTestDeployHeight, &pTestDeployedOn, angles ) == true )
+ {
+ if ( flLeft == 0 ) // first sweep is authoritative on deploy height and entity
+ {
+ *flDeployedHeight = flTestDeployHeight;
+ *pDeployedOn = pTestDeployedOn;
+ }
+ else if ( abs( *flDeployedHeight - flTestDeployHeight ) > 20 )
+ {
+ // don't allow yaw to a position that is too different in height
+ break;
+ }
+
+ *flYawLimitLeft = flLeft;
+ }
+ else
+ {
+ break;
+ }
+ flLeft += flAngleDelta;
+ }
+
+ // can't deploy here, drop out early
+ if ( flLeft <= 0 )
+ return false;
+
+ // we already tested directly ahead and it was clear. skip one test
+ flRight += flAngleDelta;
+
+ // Sweep Right
+ while ( flRight <= flMaxYaw )
+ {
+ angles[YAW] = flSaveYaw - flRight;
+
+ if ( TestDeployAngle( pPlayer, &flTestDeployHeight, &pTestDeployedOn, angles ) == true )
+ {
+ if ( abs( *flDeployedHeight - flTestDeployHeight ) > 20 )
+ {
+ // don't allow yaw to a position that is too different in height
+ break;
+ }
+
+ *flYawLimitRight = flRight;
+ }
+ else
+ {
+ break;
+ }
+ flRight += flAngleDelta;
+ }
+
+ bSuccess = true;
+ }
+
+ return bSuccess;
+}
+
+//ConVar dod_deploy_box_size( "dod_deploy_box_size", "8", FCVAR_REPLICATED );
+
+#include "util_shared.h"
+
+// trace filter that ignores all players except the passed one
+class CTraceFilterIgnorePlayersExceptFor : public CTraceFilterSimple
+{
+public:
+ // It does have a base, but we'll never network anything below here..
+ DECLARE_CLASS( CTraceFilterIgnorePlayersExceptFor, CTraceFilterSimple );
+
+ CTraceFilterIgnorePlayersExceptFor( const IHandleEntity *passentity, int collisionGroup )
+ : CTraceFilterSimple( passentity, collisionGroup )
+ {
+ }
+
+ virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
+ {
+ CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );
+
+ if ( pEntity->IsPlayer() )
+ {
+ if ( pEntity != GetPassEntity() )
+ {
+ return false;
+ }
+ else
+ return true;
+ }
+
+ return true;
+ }
+};
+
+#define DEPLOY_DOWNTRACE_FORWARD_DIST 16
+#define DEPLOY_DOWNTRACE_OFFSET 16 // yay for magic numbers
+
+bool CDODBipodWeapon::TestDeployAngle( CDODPlayer *pPlayer, float *flDeployedHeight, CBaseEntity **pDeployedOn, QAngle angles )
+{
+ // make sure we are deployed on the same entity at the same height
+ trace_t tr;
+
+ angles[PITCH] = 0;
+
+ Vector forward, right, up;
+ AngleVectors( angles, &forward, &right, &up );
+
+ // start at top of player bbox
+ Vector vecStart = pPlayer->GetAbsOrigin();
+
+ float flForwardTraceDist = 32;
+
+ // check us as ducking if we are ducked, or if were ducked when we were deployed
+ bool bDucking = pPlayer->m_Shared.IsDucking() || ( IsDeployed() && m_bDuckedWhenDeployed );
+
+ if ( pPlayer->m_Shared.IsProne() )
+ {
+ vecStart.z += VEC_PRONE_HULL_MAX[2];
+ flForwardTraceDist = 16;
+ }
+ else if ( bDucking )
+ {
+ vecStart.z += VEC_DUCK_HULL_MAX[2];
+ }
+ else
+ {
+ vecStart.z += 60;
+ }
+
+ int dim = 1; // dod_deploy_box_size.GetInt();
+ Vector vecDeployTraceBoxSize( dim, dim, dim );
+
+ vecStart.z -= vecDeployTraceBoxSize[2];
+ vecStart.z -= 4;
+
+ // sandbags are around 50 units high. Shouldn't be able to deploy on anything a lot higher than that
+
+ // optimal standing height ( for animation's sake ) is around 42 units
+ // optimal ducking height is around 20 units ( 20 unit high object, plus 8 units of gun )
+
+ // Start one half box width away from the edge of the player hull
+ Vector vecForwardStart = vecStart + forward * ( VEC_HULL_MAX_SCALED( pPlayer )[0] + vecDeployTraceBoxSize[0] );
+
+ int traceMask = MASK_SOLID;
+
+ CBaseEntity *pDeployedOnPlayer = NULL;
+
+ if ( m_hDeployedOnEnt && m_hDeployedOnEnt->IsPlayer() )
+ {
+ pDeployedOnPlayer = m_hDeployedOnEnt.Get();
+ }
+
+ CTraceFilterIgnorePlayersExceptFor deployedFilter( pDeployedOnPlayer, COLLISION_GROUP_NONE );
+ CTraceFilterSimple undeployedFilter( pPlayer, COLLISION_GROUP_NONE );
+
+ // if we're deployed, skip all players except for the deployed on player
+ // if we're not, only skip ourselves
+ ITraceFilter *filter;
+ if ( IsDeployed() )
+ filter = &deployedFilter;
+ else
+ filter = &undeployedFilter;
+
+ UTIL_TraceHull( vecForwardStart,
+ vecForwardStart + forward * ( flForwardTraceDist - 2 * vecDeployTraceBoxSize[0] ),
+ -vecDeployTraceBoxSize,
+ vecDeployTraceBoxSize,
+ traceMask,
+ filter,
+ &tr );
+
+#ifndef CLIENT_DLL
+ if ( dod_debugmgdeploy.GetBool() )
+ {
+ NDebugOverlay::Line( vecForwardStart, vecForwardStart + forward * ( flForwardTraceDist - 2 * vecDeployTraceBoxSize[0] ), 0, 0, 255, true, 0.1 );
+ NDebugOverlay::Box( vecForwardStart, -vecDeployTraceBoxSize, vecDeployTraceBoxSize, 255, 0, 0, 128, 0.1 );
+ NDebugOverlay::Box( tr.endpos, -vecDeployTraceBoxSize, vecDeployTraceBoxSize, 0, 0, 255, 128, 0.1 );
+ }
+#endif
+
+ // Test forward, are we trying to deploy into a solid object?
+ if ( tr.fraction < 1.0 )
+ {
+ return false;
+ }
+
+ // If we're prone, we can always deploy, don't do the ground test
+ if ( pPlayer->m_Shared.IsProne() && !pPlayer->m_Shared.IsGettingUpFromProne() )
+ {
+ // MATTTODO: do trace from *front* of player, not from the edge of crouch hull
+ // this is sufficient
+ *flDeployedHeight = PRONE_DEPLOY_HEIGHT;
+ return true;
+ }
+
+ // fix prediction hitch when coming up from prone. client thinks we aren't
+ // prone, but hull is still prone hull
+ // assumes prone hull is shorter than duck hull!
+ if ( pPlayer->WorldAlignMaxs().z <= VEC_PRONE_HULL_MAX.z )
+ return false;
+
+ // Else trace down
+ Vector vecDownTraceStart = vecStart + forward * ( VEC_HULL_MAX_SCALED( pPlayer )[0] + DEPLOY_DOWNTRACE_FORWARD_DIST );
+ int iTraceHeight = -( pPlayer->WorldAlignMaxs().z );
+
+
+ // search down from the forward trace
+ // use the farthest point first. If that fails, move towards the player a few times
+ // to see if they are trying to deploy on a thin railing
+
+ bool bFound = false;
+
+ int maxAttempts = 4;
+ float flHighestTraceEnd = vecDownTraceStart.z + iTraceHeight;
+ CBaseEntity *pBestDeployEnt = NULL;
+
+ while( maxAttempts > 0 )
+ {
+ UTIL_TraceHull( vecDownTraceStart,
+ vecDownTraceStart + Vector(0,0,iTraceHeight), // trace forward one box width
+ -vecDeployTraceBoxSize,
+ vecDeployTraceBoxSize,
+ traceMask,
+ filter,
+ &tr );
+
+#ifndef CLIENT_DLL
+ if ( dod_debugmgdeploy.GetBool() )
+ {
+ NDebugOverlay::Line( vecDownTraceStart, tr.endpos, 255, 0, 0, true, 0.1 );
+ NDebugOverlay::Box( vecDownTraceStart, -vecDeployTraceBoxSize, vecDeployTraceBoxSize, 255, 0, 0, 128, 0.1 );
+ NDebugOverlay::Box( tr.endpos, -vecDeployTraceBoxSize, vecDeployTraceBoxSize, 0, 0, 255, 128, 0.1 );
+ }
+#endif
+
+ bool bSuccess = ( tr.fraction < 1.0 ) && !tr.startsolid && !tr.allsolid;
+
+ // if this is the first one found, set found flag
+ if ( bSuccess && !bFound )
+ {
+ bFound = true;
+ }
+ else if ( bFound == true && bSuccess == false )
+ {
+ // it failed and we have some data. break here
+ break;
+ }
+
+ // if this trace is better ( higher ) use this one
+ if ( tr.endpos.z > flHighestTraceEnd )
+ {
+ flHighestTraceEnd = tr.endpos.z;
+ pBestDeployEnt = tr.m_pEnt;
+ }
+
+ --maxAttempts;
+
+ // move towards the player, looking for a better height to deploy on
+ vecDownTraceStart += forward * -4;
+ }
+
+ if ( bFound == false || pBestDeployEnt == NULL )
+ return false;
+
+ *pDeployedOn = pBestDeployEnt;
+ *flDeployedHeight = flHighestTraceEnd - vecDeployTraceBoxSize[0] + DEPLOY_DOWNTRACE_OFFSET - pPlayer->GetAbsOrigin().z;
+ return true;
+}
+
+Activity CDODBipodWeapon::GetUndeployActivity( void )
+{
+ return ACT_VM_UNDEPLOY;
+}
+
+Activity CDODBipodWeapon::GetDeployActivity( void )
+{
+ return ACT_VM_DEPLOY;
+}
+
+
+Activity CDODBipodWeapon::GetPrimaryAttackActivity( void )
+{
+ Activity actPrim;
+
+ if( IsDeployed() )
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED;
+ else
+ actPrim = ACT_VM_PRIMARYATTACK;
+
+ return actPrim;
+}
+
+Activity CDODBipodWeapon::GetReloadActivity( void )
+{
+ Activity actReload;
+
+ if( IsDeployed() )
+ actReload = ACT_VM_RELOAD_DEPLOYED;
+ else
+ actReload = ACT_VM_RELOAD;
+
+ return actReload;
+}
+
+Activity CDODBipodWeapon::GetIdleActivity( void )
+{
+ Activity actIdle;
+
+ if( IsDeployed() )
+ actIdle = ACT_VM_IDLE_DEPLOYED;
+ else
+ actIdle = ACT_VM_IDLE;
+
+ return actIdle;
+}
+
+
+float CDODBipodWeapon::GetWeaponAccuracy( float flPlayerSpeed )
+{
+ float flSpread = BaseClass::GetWeaponAccuracy( flPlayerSpeed );
+
+ if( IsDeployed() )
+ {
+ flSpread = m_pWeaponInfo->m_flSecondaryAccuracy;
+ }
+
+ return flSpread;
+}
+
+#ifdef CLIENT_DLL
+
+ int CDODBipodWeapon::GetWorldModelIndex( void )
+ {
+ if( GetOwner() == NULL )
+ return m_iWorldModelIndex;
+ else if( m_bUseAltWeaponModel )
+ return m_iWorldModelIndex; //override for hand signals etc
+ else
+ return m_iCurrentWorldModel;
+ }
+
+ void CDODBipodWeapon::CheckForAltWeapon( int iCurrentState )
+ {
+ int iCriteria = GetDODWpnData().m_iAltWpnCriteria;
+
+ bool bReloading = ( iCurrentState & ALTWPN_CRITERIA_RELOADING );
+
+ if( bReloading )
+ {
+ if( IsDeployed() && iCurrentState & ALTWPN_CRITERIA_PRONE &&
+ iCriteria & ALTWPN_CRITERIA_PRONE_DEPLOYED_RELOAD )
+ {
+ m_iCurrentWorldModel = m_iProneDeployedReloadModelIndex; // prone deployed reload
+ }
+ else if( IsDeployed() && iCriteria & ALTWPN_CRITERIA_DEPLOYED_RELOAD )
+ {
+ m_iCurrentWorldModel = m_iDeployedReloadModelIndex; // deployed reload
+ }
+ else if( iCriteria & ALTWPN_CRITERIA_RELOADING )
+ {
+ m_iCurrentWorldModel = m_iReloadModelIndex; // left handed reload
+ }
+ else
+ {
+ m_iCurrentWorldModel = m_iWorldModelIndex; // normal weapon reload
+ }
+ }
+ else if( IsDeployed() && iCriteria & ALTWPN_CRITERIA_DEPLOYED )
+ {
+ m_iCurrentWorldModel = m_iDeployedModelIndex; // bipod down
+ }
+ else if( (iCurrentState & iCriteria) & ALTWPN_CRITERIA_FIRING )
+ {
+ // don't think we have any weapons that do this
+ m_iCurrentWorldModel = m_iReloadModelIndex; // left handed shooting?
+ }
+ else
+ {
+ m_iCurrentWorldModel = m_iWorldModelIndex; // normal weapon
+ }
+ }
+
+ ConVar deployed_mg_sensitivity( "deployed_mg_sensitivity", "0.9", FCVAR_CHEAT, "Mouse sensitivity while deploying a machine gun" );
+
+ void CDODBipodWeapon::OverrideMouseInput( float *x, float *y )
+ {
+ if( IsDeployed() )
+ {
+ float flSensitivity = deployed_mg_sensitivity.GetFloat();
+
+ *x *= flSensitivity;
+ *y *= flSensitivity;
+ }
+ }
+
+#endif
diff --git a/game/shared/dod/weapon_dodbipodgun.h b/game/shared/dod/weapon_dodbipodgun.h
new file mode 100644
index 0000000..7c0bb56
--- /dev/null
+++ b/game/shared/dod/weapon_dodbipodgun.h
@@ -0,0 +1,92 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "shake.h"
+#include "weapon_dodfullauto.h"
+
+#if defined( CLIENT_DLL )
+ #define CDODBipodWeapon C_DODBipodWeapon
+#endif
+
+class CDODBipodWeapon : public CDODFullAutoWeapon
+{
+public:
+ DECLARE_CLASS( CDODBipodWeapon, CDODFullAutoWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CDODBipodWeapon();
+
+ virtual void Spawn();
+ virtual void Precache();
+ virtual void Drop( const Vector &vecVelocity );
+ virtual void SecondaryAttack( void );
+ virtual bool Reload( void );
+
+ virtual float GetWeaponAccuracy( float flPlayerSpeed );
+
+ virtual Activity GetUndeployActivity( void );
+ virtual Activity GetDeployActivity( void );
+ virtual Activity GetPrimaryAttackActivity( void );
+ virtual Activity GetReloadActivity( void );
+ virtual Activity GetIdleActivity( void );
+
+ virtual bool CanDrop( void );
+ virtual bool CanHolster( void );
+
+ inline void SetDeployed( bool bDeployed );
+ inline bool IsDeployed( void ) { return m_bDeployed; }
+
+ virtual void ItemBusyFrame( void );
+ virtual void ItemPostFrame( void );
+ void BipodThink( void );
+
+ bool AttemptToDeploy( void );
+ bool CheckDeployEnt( void );
+
+ bool TestDeploy( float *flDeployedHeight, CBaseEntity **pDeployedOn, float *flYawLimitLeft = NULL, float *flYawLimitRight = NULL );
+ bool TestDeployAngle( CDODPlayer *pPlayer, float *flDeployedHeight, CBaseEntity **pDeployedOn, QAngle angles );
+
+ bool FindYawLimits( float *flLeftLimit, float *flRightLimit );
+
+ virtual void DoFireEffects();
+
+ void DeployBipod( float flHeight, CBaseEntity *pDeployedOn, float flYawLimitLeft, float flYawLimitRight );
+ void UndeployBipod( void );
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_NONE; }
+
+#ifdef CLIENT_DLL
+ virtual int GetWorldModelIndex( void );
+ virtual void CheckForAltWeapon( int iCurrentState );
+
+ virtual void OverrideMouseInput( float *x, float *y );
+#endif
+
+private:
+ CDODBipodWeapon( const CDODBipodWeapon & );
+
+ CNetworkVar( bool, m_bDeployed );
+
+ CNetworkVar( int, m_iDeployedModelIndex );
+ CNetworkVar( int, m_iDeployedReloadModelIndex );
+ CNetworkVar( int, m_iProneDeployedReloadModelIndex );
+
+ int m_iCurrentWorldModel;
+
+ EHANDLE m_hDeployedOnEnt;
+ float m_flDeployedHeight;
+ float m_flNextDeployCheckTime;
+
+ Vector m_DeployedEntOrigin;
+
+ bool m_bDuckedWhenDeployed;
+
+#ifdef CLIENT_DLL
+ bool m_bUseDeployedReload;
+#endif
+};
diff --git a/game/shared/dod/weapon_dodfireselect.cpp b/game/shared/dod/weapon_dodfireselect.cpp
new file mode 100644
index 0000000..9b1038a
--- /dev/null
+++ b/game/shared/dod/weapon_dodfireselect.cpp
@@ -0,0 +1,211 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "fx_dod_shared.h"
+#include "weapon_dodfireselect.h"
+
+#ifdef CLIENT_DLL
+ #include "prediction.h"
+#endif
+
+IMPLEMENT_NETWORKCLASS_ALIASED( DODFireSelectWeapon, DT_FireSelectWeapon )
+
+
+BEGIN_NETWORK_TABLE( CDODFireSelectWeapon, DT_FireSelectWeapon )
+#ifdef CLIENT_DLL
+ RecvPropBool( RECVINFO( m_bSemiAuto ) )
+#else
+ SendPropBool( SENDINFO( m_bSemiAuto ) )
+#endif
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CDODFireSelectWeapon )
+END_PREDICTION_DATA()
+
+
+CDODFireSelectWeapon::CDODFireSelectWeapon()
+{
+}
+
+void CDODFireSelectWeapon::Spawn( void )
+{
+ m_bSemiAuto = false;
+
+#ifdef CLIENT_DLL
+ ResetViewModelAnimDir();
+#endif
+
+ m_iAltFireHint = HINT_USE_SEMI_AUTO;
+
+ BaseClass::Spawn();
+}
+
+void CDODFireSelectWeapon::PrimaryAttack( void )
+{
+ if ( IsSemiAuto() )
+ {
+ // If semi auto, set this flag which will prevent us from
+ // attacking again until the button is released.
+ m_bInAttack = true;
+ }
+
+ BaseClass::PrimaryAttack();
+}
+
+float CDODFireSelectWeapon::GetFireDelay( void )
+{
+ if ( IsSemiAuto() )
+ {
+ return m_pWeaponInfo->m_flSecondaryFireDelay;
+ }
+ else
+ {
+ return m_pWeaponInfo->m_flFireDelay;
+ }
+}
+
+void CDODFireSelectWeapon::SecondaryAttack( void )
+{
+ // toggle fire mode ( full auto, semi auto )
+ m_bSemiAuto = !m_bSemiAuto;
+
+#ifndef CLIENT_DLL
+ CDODPlayer *pPlayer = GetDODPlayerOwner();
+ if ( pPlayer )
+ {
+ pPlayer->RemoveHintTimer( m_iAltFireHint );
+ }
+#endif
+
+ if ( m_bSemiAuto )
+ {
+#ifdef CLIENT_DLL
+ if ( prediction->IsFirstTimePredicted() )
+ {
+ m_flPosChangeTimer = gpGlobals->curtime;
+ m_bAnimToSemiAuto = false;
+ }
+#endif
+
+ SendWeaponAnim( ACT_VM_UNDEPLOY );
+ }
+ else
+ {
+#ifdef CLIENT_DLL
+ if ( prediction->IsFirstTimePredicted() )
+ {
+ m_flPosChangeTimer = gpGlobals->curtime;
+ m_bAnimToSemiAuto = true;
+ }
+#endif
+
+ SendWeaponAnim( ACT_VM_DEPLOY );
+ }
+
+#ifdef CLIENT_DLL
+ if ( prediction->IsFirstTimePredicted() )
+ {
+ m_flPosChangeTimer = gpGlobals->curtime;
+ }
+#endif
+
+ m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+}
+
+bool CDODFireSelectWeapon::IsSemiAuto( void )
+{
+ return m_bSemiAuto;
+}
+
+float CDODFireSelectWeapon::GetWeaponAccuracy( float flPlayerSpeed )
+{
+ float flSpread;
+
+ if ( IsSemiAuto() )
+ flSpread = m_pWeaponInfo->m_flSecondaryAccuracy;
+ else
+ flSpread = m_pWeaponInfo->m_flAccuracy;
+
+ if( flPlayerSpeed > 45 )
+ flSpread += m_pWeaponInfo->m_flAccuracyMovePenalty;
+
+ return flSpread;
+}
+
+Activity CDODFireSelectWeapon::GetIdleActivity( void )
+{
+ if ( !IsSemiAuto() )
+ return ACT_VM_IDLE_DEPLOYED;
+
+ return BaseClass::GetIdleActivity();
+}
+
+Activity CDODFireSelectWeapon::GetPrimaryAttackActivity( void )
+{
+ if ( !IsSemiAuto() )
+ return ACT_VM_PRIMARYATTACK_DEPLOYED;
+
+ return BaseClass::GetPrimaryAttackActivity();
+}
+
+Activity CDODFireSelectWeapon::GetReloadActivity( void )
+{
+ if ( !IsSemiAuto() )
+ return ACT_VM_RELOAD_DEPLOYED;
+
+ return BaseClass::GetReloadActivity();
+}
+
+Activity CDODFireSelectWeapon::GetDrawActivity( void )
+{
+ if ( !IsSemiAuto() )
+ return ACT_VM_DRAW_DEPLOYED;
+
+ return BaseClass::GetDrawActivity();
+}
+
+void CDODFireSelectWeapon::Drop( const Vector &vecVelocity )
+{
+ // always full auto when you pick up a weapon
+ m_bSemiAuto = false;
+
+ return BaseClass::Drop( vecVelocity );
+}
+
+#ifdef CLIENT_DLL
+ Vector CDODFireSelectWeapon::GetDesiredViewModelOffset( C_DODPlayer *pOwner )
+ {
+ Vector viewOffset = pOwner->GetViewOffset();
+
+ float flPercent = ( viewOffset.z - VEC_PRONE_VIEW_SCALED( pOwner ).z ) / ( VEC_VIEW_SCALED( pOwner ).z - VEC_PRONE_VIEW_SCALED( pOwner ).z );
+
+ Vector offset = ( flPercent * GetDODWpnData().m_vecViewNormalOffset +
+ ( 1.0 - flPercent ) * GetDODWpnData().m_vecViewProneOffset );
+
+ static float flLastPercent = 0;
+
+ if ( prediction->InPrediction() )
+ {
+ return ( flLastPercent * offset +
+ ( 1.0 - flLastPercent ) * GetDODWpnData().m_vecViewProneOffset );
+ }
+
+ float timer = gpGlobals->curtime - m_flPosChangeTimer;
+
+ // how long since we changed iron sight mode
+ float flPosChangePercent = clamp( ( timer / ( 0.3 ) ), 0.0, 1.0 );
+
+ float flZoomPercent = ( m_bAnimToSemiAuto ? ( 1.0 - flPosChangePercent ) : flPosChangePercent );
+
+ // store this value to use when called in prediction
+ flLastPercent = flZoomPercent;
+
+ return ( flZoomPercent * GetDODWpnData().m_vecIronSightOffset +
+ ( 1.0 - flZoomPercent ) * offset );
+ }
+#endif
diff --git a/game/shared/dod/weapon_dodfireselect.h b/game/shared/dod/weapon_dodfireselect.h
new file mode 100644
index 0000000..2e00edb
--- /dev/null
+++ b/game/shared/dod/weapon_dodfireselect.h
@@ -0,0 +1,73 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WEAPON_DODFIRESELECT_H
+#define WEAPON_DODFIRESELECT_H
+
+#include "cbase.h"
+#include "weapon_dodbasegun.h"
+
+#if defined( CLIENT_DLL )
+#define CDODFireSelectWeapon C_DODFireSelectWeapon
+
+#include "c_dod_player.h"
+#endif
+
+class CDODFireSelectWeapon : public CWeaponDODBaseGun
+{
+public:
+ DECLARE_CLASS( CDODFireSelectWeapon, CWeaponDODBaseGun );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CDODFireSelectWeapon();
+
+ virtual void Spawn();
+ virtual void PrimaryAttack( void );
+ virtual void SecondaryAttack( void );
+ virtual float GetWeaponAccuracy( float flPlayerSpeed );
+ virtual float GetFireDelay( void );
+ virtual void Drop( const Vector &vecVelocity );
+
+ bool IsSemiAuto( void );
+
+ virtual Activity GetIdleActivity( void );
+ virtual Activity GetPrimaryAttackActivity( void );
+ virtual Activity GetReloadActivity( void );
+ virtual Activity GetDrawActivity( void );
+
+#ifdef CLIENT_DLL
+ virtual Vector GetDesiredViewModelOffset( C_DODPlayer *pOwner );
+
+ void ResetViewModelAnimDir( void )
+ {
+ m_bAnimToSemiAuto = true;
+ m_flPosChangeTimer = 0;
+ }
+
+ virtual void OnWeaponDropped( void )
+ {
+ ResetViewModelAnimDir();
+
+ m_bSemiAuto = false;
+
+ BaseClass::OnWeaponDropped();
+ }
+#endif
+
+private:
+ CNetworkVar( bool, m_bSemiAuto );
+
+#ifdef CLIENT_DLL
+ bool m_bAnimToSemiAuto;
+ float m_flPosChangeTimer;
+#endif
+
+private:
+ CDODFireSelectWeapon( const CDODFireSelectWeapon & );
+};
+
+#endif //WEAPON_DODFIRESELECT_H \ No newline at end of file
diff --git a/game/shared/dod/weapon_dodfullauto.cpp b/game/shared/dod/weapon_dodfullauto.cpp
new file mode 100644
index 0000000..08e2b4b
--- /dev/null
+++ b/game/shared/dod/weapon_dodfullauto.cpp
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "fx_dod_shared.h"
+#include "weapon_dodfullauto.h"
+
+IMPLEMENT_NETWORKCLASS_ALIASED( DODFullAutoWeapon, DT_FullAutoWeapon )
+
+BEGIN_NETWORK_TABLE( CDODFullAutoWeapon, DT_FullAutoWeapon )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CDODFullAutoWeapon )
+END_PREDICTION_DATA()
+
+
+CDODFullAutoWeapon::CDODFullAutoWeapon()
+{
+}
+
+void CDODFullAutoWeapon::Spawn()
+{
+ BaseClass::Spawn();
+}
+
+void CDODFullAutoWeapon::PrimaryAttack( void )
+{
+ BaseClass::PrimaryAttack();
+} \ No newline at end of file
diff --git a/game/shared/dod/weapon_dodfullauto.h b/game/shared/dod/weapon_dodfullauto.h
new file mode 100644
index 0000000..6cf36a8
--- /dev/null
+++ b/game/shared/dod/weapon_dodfullauto.h
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WEAPON_DODFULLAUTO_H
+#define WEAPON_DODFULLAUTO_H
+
+#include "cbase.h"
+#include "shake.h"
+#include "weapon_dodbasegun.h"
+
+#if defined( CLIENT_DLL )
+ #define CDODFullAutoWeapon C_DODFullAutoWeapon
+#endif
+
+class CDODFullAutoWeapon : public CWeaponDODBaseGun
+{
+public:
+ DECLARE_CLASS( CDODFullAutoWeapon, CWeaponDODBaseGun );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CDODFullAutoWeapon();
+
+ virtual void Spawn();
+ virtual void PrimaryAttack( void );
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_NONE; }
+
+private:
+ CDODFullAutoWeapon( const CDODFullAutoWeapon & );
+};
+
+#endif //WEAPON_DODFULLAUTO_H \ No newline at end of file
diff --git a/game/shared/dod/weapon_dodfullauto_punch.cpp b/game/shared/dod/weapon_dodfullauto_punch.cpp
new file mode 100644
index 0000000..9f67a3a
--- /dev/null
+++ b/game/shared/dod/weapon_dodfullauto_punch.cpp
@@ -0,0 +1,84 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodfullauto_punch.h"
+#include "in_buttons.h"
+#include "dod_shareddefs.h"
+
+#ifndef CLIENT_DLL
+#include "dod_player.h"
+#endif
+
+IMPLEMENT_NETWORKCLASS_ALIASED( DODFullAutoPunchWeapon, DT_FullAutoPunchWeapon )
+
+BEGIN_NETWORK_TABLE( CDODFullAutoPunchWeapon, DT_FullAutoPunchWeapon )
+END_NETWORK_TABLE()
+
+#ifdef CLIENT_DLL
+BEGIN_PREDICTION_DATA( CDODFullAutoPunchWeapon )
+END_PREDICTION_DATA()
+#endif
+
+void CDODFullAutoPunchWeapon::Spawn( void )
+{
+ m_iAltFireHint = HINT_USE_MELEE;
+
+ BaseClass::Spawn();
+}
+
+void CDODFullAutoPunchWeapon::SecondaryAttack( void )
+{
+ if ( m_bInReload )
+ {
+ m_bInReload = false;
+ GetPlayerOwner()->m_flNextAttack = gpGlobals->curtime;
+ }
+ else if ( GetPlayerOwner()->m_flNextAttack > gpGlobals->curtime )
+ {
+ return;
+ }
+
+ Punch();
+
+ // start calling ItemPostFrame
+ GetPlayerOwner()->m_flNextAttack = gpGlobals->curtime;
+
+ m_flNextPrimaryAttack = m_flNextSecondaryAttack;
+
+#ifndef CLIENT_DLL
+ CDODPlayer *pPlayer = GetDODPlayerOwner();
+ if ( pPlayer )
+ {
+ pPlayer->RemoveHintTimer( m_iAltFireHint );
+ }
+#endif
+}
+
+bool CDODFullAutoPunchWeapon::Reload( void )
+{
+ bool bSuccess = BaseClass::Reload();
+
+ if ( bSuccess )
+ {
+ m_flNextSecondaryAttack = gpGlobals->curtime;
+ }
+
+ return bSuccess;
+}
+
+void CDODFullAutoPunchWeapon::ItemBusyFrame( void )
+{
+ BaseClass::ItemBusyFrame();
+
+ CBasePlayer *pPlayer = GetPlayerOwner();
+
+ if ( pPlayer && (pPlayer->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime))
+ {
+ SecondaryAttack();
+ pPlayer->m_nButtons &= ~IN_ATTACK2;
+ }
+}
diff --git a/game/shared/dod/weapon_dodfullauto_punch.h b/game/shared/dod/weapon_dodfullauto_punch.h
new file mode 100644
index 0000000..5dcee58
--- /dev/null
+++ b/game/shared/dod/weapon_dodfullauto_punch.h
@@ -0,0 +1,34 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodfullauto.h"
+
+#if defined( CLIENT_DLL )
+ #define CDODFullAutoPunchWeapon C_DODFullAutoPunchWeapon
+#endif
+
+class CDODFullAutoPunchWeapon : public CDODFullAutoWeapon
+{
+public:
+ DECLARE_CLASS( CDODFullAutoPunchWeapon, CDODFullAutoWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CDODFullAutoPunchWeapon() {}
+
+ virtual void Spawn( void );
+ virtual void SecondaryAttack( void );
+ virtual bool Reload( void );
+ virtual void ItemBusyFrame( void );
+
+ virtual const char *GetSecondaryDeathNoticeName( void ) { return "punch"; }
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_NONE; }
+
+private:
+ CDODFullAutoPunchWeapon( const CDODFullAutoPunchWeapon & );
+}; \ No newline at end of file
diff --git a/game/shared/dod/weapon_dodsemiauto.cpp b/game/shared/dod/weapon_dodsemiauto.cpp
new file mode 100644
index 0000000..e0aaeaf
--- /dev/null
+++ b/game/shared/dod/weapon_dodsemiauto.cpp
@@ -0,0 +1,37 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodsemiauto.h"
+
+IMPLEMENT_NETWORKCLASS_ALIASED( DODSemiAutoWeapon, DT_SemiAutoWeapon )
+
+BEGIN_NETWORK_TABLE( CDODSemiAutoWeapon, DT_SemiAutoWeapon )
+END_NETWORK_TABLE()
+
+#ifdef CLIENT_DLL
+BEGIN_PREDICTION_DATA( CDODSemiAutoWeapon )
+END_PREDICTION_DATA()
+#endif
+
+CDODSemiAutoWeapon::CDODSemiAutoWeapon()
+{
+}
+
+void CDODSemiAutoWeapon::Spawn()
+{
+ BaseClass::Spawn();
+}
+
+void CDODSemiAutoWeapon::PrimaryAttack( void )
+{
+ //Don't attack more than once on the same button press.
+ //m_bInAttack is set to false when the attack button is released
+
+ m_bInAttack = true;
+
+ BaseClass::PrimaryAttack();
+} \ No newline at end of file
diff --git a/game/shared/dod/weapon_dodsemiauto.h b/game/shared/dod/weapon_dodsemiauto.h
new file mode 100644
index 0000000..bda1437
--- /dev/null
+++ b/game/shared/dod/weapon_dodsemiauto.h
@@ -0,0 +1,40 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WEAPON_DODSEMIAUTO_H
+#define WEAPON_DODSEMIAUTO_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "cbase.h"
+#include "shake.h"
+#include "weapon_dodbasegun.h"
+
+
+#if defined( CLIENT_DLL )
+ #define CDODSemiAutoWeapon C_DODSemiAutoWeapon
+#endif
+
+class CDODSemiAutoWeapon : public CWeaponDODBaseGun
+{
+public:
+ DECLARE_CLASS( CDODSemiAutoWeapon, CWeaponDODBaseGun );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CDODSemiAutoWeapon();
+
+ virtual void Spawn();
+ virtual void PrimaryAttack( void );
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_NONE; }
+
+private:
+ CDODSemiAutoWeapon( const CDODSemiAutoWeapon & );
+};
+
+#endif //WEAPON_DODSEMIAUTO_H \ No newline at end of file
diff --git a/game/shared/dod/weapon_dodsniper.cpp b/game/shared/dod/weapon_dodsniper.cpp
new file mode 100644
index 0000000..70d3568
--- /dev/null
+++ b/game/shared/dod/weapon_dodsniper.cpp
@@ -0,0 +1,414 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "fx_dod_shared.h"
+#include "weapon_dodsniper.h"
+
+#ifdef CLIENT_DLL
+ #include "prediction.h"
+#endif
+
+IMPLEMENT_NETWORKCLASS_ALIASED( DODSniperWeapon, DT_SniperWeapon )
+
+#ifdef CLIENT_DLL
+
+ void RecvProxy_AnimStart( const CRecvProxyData *pData, void *pStruct, void *pOut )
+ {
+ CDODSniperWeapon *pWpn = (CDODSniperWeapon *) pStruct;
+ pWpn->m_bDoViewAnim = ( pData->m_Value.m_Int > 0 );
+ }
+
+#endif
+
+BEGIN_NETWORK_TABLE( CDODSniperWeapon, DT_SniperWeapon )
+ #ifdef CLIENT_DLL
+ RecvPropBool( RECVINFO( m_bZoomed ) ),
+ RecvPropInt( RECVINFO( m_bDoViewAnim ), 0, RecvProxy_AnimStart )
+ #else
+ SendPropBool( SENDINFO( m_bZoomed ) ),
+ SendPropBool( SENDINFO( m_bDoViewAnim ) )
+ #endif
+END_NETWORK_TABLE()
+
+
+#ifdef CLIENT_DLL
+
+ BEGIN_PREDICTION_DATA( CDODSniperWeapon )
+ DEFINE_PRED_FIELD( m_bZoomed, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE )
+ END_PREDICTION_DATA()
+
+#else
+
+ BEGIN_DATADESC( CDODSniperWeapon )
+ END_DATADESC()
+
+#endif
+
+
+CDODSniperWeapon::CDODSniperWeapon()
+{
+}
+
+void CDODSniperWeapon::Spawn( void )
+{
+ BaseClass::Spawn();
+
+ ResetTimers();
+
+#ifdef CLIENT_DLL
+ m_bDoViewAnimCache = false;
+ m_flZoomPercent = 0.0f;
+#endif
+
+ m_bShouldRezoomAfterShot = true;
+}
+
+void CDODSniperWeapon::ResetTimers( void )
+{
+ m_flUnzoomTime = -1;
+ m_flRezoomTime = -1;
+ m_flZoomOutTime = -1;
+ m_flZoomInTime = -1;
+ m_bRezoomAfterShot = false;
+ m_bRezoomAfterReload = false;
+}
+
+bool CDODSniperWeapon::Holster( CBaseCombatWeapon *pSwitchingTo )
+{
+#ifndef CLIENT_DLL
+ ZoomOut();
+
+ ResetTimers();
+#endif
+
+ return BaseClass::Holster( pSwitchingTo );
+}
+
+void CDODSniperWeapon::PrimaryAttack( void )
+{
+ BaseClass::PrimaryAttack();
+
+ CDODPlayer *pPlayer = ToDODPlayer( GetOwner() );
+
+ if ( IsZoomed() && ShouldZoomOutBetweenShots() )
+ {
+ //If we have more bullets, zoom out, play the bolt animation and zoom back in
+ if( m_iClip1 > 0 && m_bShouldRezoomAfterShot && ( pPlayer && pPlayer->ShouldAutoRezoom() ) )
+ {
+ SetRezoom( true, 0.5f ); // zoom out in 0.5 seconds, then rezoom
+ }
+ else //just zoom out
+ {
+ SetRezoom( false, 0.5f ); // just zoom out in 0.5 seconds
+ }
+ }
+
+ // overwrite the next secondary attack, so we can zoom sooned after we've fired
+ if ( m_bRezoomAfterShot && m_iClip1 > 0 )
+ m_flNextSecondaryAttack = gpGlobals->curtime + 2.0;
+ else
+ m_flNextSecondaryAttack = SequenceDuration();
+}
+
+void CDODSniperWeapon::SecondaryAttack( void )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+
+ Assert( pPlayer );
+
+ if ( !pPlayer )
+ return;
+
+ ToggleZoom();
+}
+
+bool CDODSniperWeapon::Reload( void )
+{
+ bool bSuccess = BaseClass::Reload();
+
+ if ( bSuccess && IsZoomed() )
+ {
+ //if ( ShouldRezoomAfterReload() )
+ // m_bRezoomAfterReload = true;
+
+ ZoomOut();
+ }
+
+ if ( !bSuccess )
+ m_bRezoomAfterReload = false;
+
+ return bSuccess;
+}
+
+void CDODSniperWeapon::FinishReload( void )
+{
+ BaseClass::FinishReload();
+
+ if ( m_bRezoomAfterReload )
+ {
+ ZoomIn();
+ m_bRezoomAfterReload = false;
+ }
+}
+
+float CDODSniperWeapon::GetWeaponAccuracy( float flPlayerSpeed )
+{
+ //snipers and deployable weapons inherit this and override when we need a different accuracy
+
+ float flSpread = m_pWeaponInfo->m_flAccuracy;
+
+ if ( IsZoomed() && ( gpGlobals->curtime - m_flZoomChangeTime ) > DOD_SNIPER_ZOOM_CHANGE_TIME )
+ {
+ flSpread = m_pWeaponInfo->m_flSecondaryAccuracy;
+ }
+
+ if( flPlayerSpeed > 45 )
+ flSpread += m_pWeaponInfo->m_flAccuracyMovePenalty;
+
+ return flSpread;
+}
+
+bool CDODSniperWeapon::IsZoomed( void )
+{
+ // check the player?
+ return IsSniperZoomed();
+}
+
+bool CDODSniperWeapon::ShouldDrawCrosshair( void )
+{
+ //if ( IsFullyZoomed() )
+ // return false;
+
+ // don't draw if we are zoomed at all
+ if ( m_bZoomed )
+ return false;
+
+ return BaseClass::ShouldDrawCrosshair();
+}
+
+#include "in_buttons.h"
+
+void CDODSniperWeapon::ItemPostFrame( void )
+{
+ if ( m_flUnzoomTime > 0 && gpGlobals->curtime > m_flUnzoomTime )
+ {
+ if ( m_bRezoomAfterShot )
+ {
+ ZoomOutIn();
+ m_bRezoomAfterShot = false;
+ }
+ else
+ {
+ ZoomOut();
+ }
+
+ m_flUnzoomTime = -1;
+ }
+
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+ Assert( pPlayer );
+
+ if ( m_flRezoomTime > 0 )
+ {
+ // if the player is sprinting and moving at all, cancel the rezoom
+ if ( ( pPlayer->m_nButtons & IN_SPEED ) > 0 &&
+ pPlayer->GetAbsVelocity().Length2D() > 20 )
+ {
+ m_flRezoomTime = -1;
+ }
+ else if ( gpGlobals->curtime > m_flRezoomTime )
+ {
+ ZoomIn();
+ m_flRezoomTime = -1;
+ }
+ }
+
+ if ( m_flZoomInTime > 0 && gpGlobals->curtime > m_flZoomInTime )
+ {
+#ifndef CLIENT_DLL
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+ Assert( pPlayer );
+ pPlayer->SetFOV( pPlayer, GetZoomedFOV(), 0.1f );
+#endif
+ m_flZoomInTime = -1;
+ m_flZoomOutTime = -1;
+ }
+
+ if ( m_flZoomInTime > 0 && (pPlayer->m_nButtons & IN_ATTACK) )
+ {
+ m_bInAttack = true;
+ }
+
+ BaseClass::ItemPostFrame();
+}
+
+void CDODSniperWeapon::Drop( const Vector &vecVelocity )
+{
+ // If a player is killed while deployed, this resets the weapon state
+ if ( IsZoomed() )
+ ZoomOut();
+
+ ResetTimers();
+
+ BaseClass::Drop( vecVelocity );
+}
+
+void CDODSniperWeapon::ToggleZoom( void )
+{
+ CDODPlayer *pPlayer = GetDODPlayerOwner();
+
+ if ( !pPlayer->m_Shared.IsJumping() )
+ {
+ if( !IsZoomed() )
+ {
+ if ( CanAttack() )
+ {
+#ifndef CLIENT_DLL
+ pPlayer->RemoveHintTimer( m_iAltFireHint );
+#endif
+
+ ZoomIn();
+ }
+ }
+ else
+ {
+ ZoomOut();
+ }
+ }
+}
+
+void CDODSniperWeapon::ZoomIn( void )
+{
+ m_flZoomInTime = gpGlobals->curtime + DOD_SNIPER_ZOOM_CHANGE_TIME;
+
+#ifndef CLIENT_DLL
+ SetZoomed( true );
+
+ m_bDoViewAnim = !m_bDoViewAnim;
+#endif
+
+ m_flNextPrimaryAttack = MAX( gpGlobals->curtime + 0.5, m_flNextPrimaryAttack );
+ m_flNextSecondaryAttack = MAX( gpGlobals->curtime + 0.5, m_flNextSecondaryAttack );
+ m_flTimeWeaponIdle = gpGlobals->curtime + m_pWeaponInfo->m_flTimeToIdleAfterFire;
+
+ m_flZoomChangeTime = gpGlobals->curtime;
+}
+
+void CDODSniperWeapon::ZoomOut( void )
+{
+ bool bWasZoomed = IsZoomed();
+
+#ifndef CLIENT_DLL
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+ Assert( pPlayer );
+
+ pPlayer->SetFOV( pPlayer, 90, 0.1f );
+ SetZoomed( false );
+
+ m_bDoViewAnim = !m_bDoViewAnim;
+#endif
+
+ if ( bWasZoomed )
+ {
+ m_flNextPrimaryAttack = MAX( gpGlobals->curtime + 0.5, m_flNextPrimaryAttack );
+ m_flNextSecondaryAttack = MAX( gpGlobals->curtime + 0.5, m_flNextSecondaryAttack );
+ m_flTimeWeaponIdle = gpGlobals->curtime + m_pWeaponInfo->m_flTimeToIdleAfterFire;
+ }
+
+ m_flZoomChangeTime = gpGlobals->curtime;
+
+ // if we are thinking about zooming, cancel it
+ m_flZoomInTime = -1;
+ m_flUnzoomTime = -1;
+ m_flRezoomTime = -1;
+}
+
+// reduce rezoome time, to account for fade in we're replacing with anim
+#define REZOOM_TIME 1.2f
+
+void CDODSniperWeapon::ZoomOutIn( void )
+{
+ ZoomOut();
+
+ m_flRezoomTime = gpGlobals->curtime + 1.0;
+}
+
+void CDODSniperWeapon::SetRezoom( bool bRezoom, float flDelay )
+{
+ m_flUnzoomTime = gpGlobals->curtime + flDelay;
+
+ m_bRezoomAfterShot = bRezoom;
+}
+
+bool CDODSniperWeapon::IsFullyZoomed( void )
+{
+ return ( IsZoomed() == true &&
+ (( gpGlobals->curtime - m_flZoomChangeTime ) > DOD_SNIPER_ZOOM_CHANGE_TIME) );
+}
+
+bool CDODSniperWeapon::IsZoomingIn( void )
+{
+ return ( m_flZoomInTime > gpGlobals->curtime );
+}
+
+#ifdef CLIENT_DLL
+
+ float CDODSniperWeapon::GetZoomedPercentage( void )
+ {
+ return m_flZoomPercent;
+ }
+
+ Vector CDODSniperWeapon::GetDesiredViewModelOffset( C_DODPlayer *pOwner )
+ {
+ static Vector vecLastResult = vec3_origin;
+
+ if ( prediction->InPrediction() && !prediction->IsFirstTimePredicted() )
+ {
+ return vecLastResult;
+ }
+
+ if ( m_bDoViewAnim != m_bDoViewAnimCache )
+ {
+ // start the anim timer
+ m_flViewAnimTimer = gpGlobals->curtime + DOD_SNIPER_ZOOM_CHANGE_TIME;
+ m_bDoViewAnimCache = m_bDoViewAnim.m_Value;
+ }
+
+ Vector viewOffset = pOwner->GetViewOffset();
+
+ float flPercent = clamp( ( viewOffset.z - VEC_PRONE_VIEW_SCALED( pOwner ).z ) / ( VEC_VIEW_SCALED( pOwner ).z - VEC_PRONE_VIEW_SCALED( pOwner ).z ), 0.0, 1.0 );
+
+ Vector offset = ( flPercent * GetDODWpnData().m_vecViewNormalOffset +
+ ( 1.0 - flPercent ) * GetDODWpnData().m_vecViewProneOffset );
+
+
+ // how long since we changed iron sight mode
+ float flZoomAnimPercent = clamp( ( (m_flViewAnimTimer - gpGlobals->curtime) / ( DOD_SNIPER_ZOOM_CHANGE_TIME ) ), 0.0, 1.0 );
+
+ m_flZoomPercent = ( IsZoomed() ? ( 1.0 - flZoomAnimPercent ) : flZoomAnimPercent );
+
+ //Msg( "(%.1f) zoom %.2f %.2f\n", gpGlobals->curtime, m_flViewAnimTimer - gpGlobals->curtime, m_flZoomPercent );
+
+ // use that percent to interp to iron sight position
+ Vector vecResult = ( m_flZoomPercent * GetDODWpnData().m_vecIronSightOffset +
+ ( 1.0 - m_flZoomPercent ) * offset );
+
+ // store this value to use when called in prediction
+ vecLastResult = vecResult;
+
+ return vecResult;
+ }
+
+ float CDODSniperWeapon::GetViewModelSwayScale( void )
+ {
+ if ( IsFullyZoomed() )
+ return 0;
+
+ return BaseClass::GetViewModelSwayScale();
+ }
+
+#endif //CLIENT_DLL
diff --git a/game/shared/dod/weapon_dodsniper.h b/game/shared/dod/weapon_dodsniper.h
new file mode 100644
index 0000000..da6fefe
--- /dev/null
+++ b/game/shared/dod/weapon_dodsniper.h
@@ -0,0 +1,111 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WEAPON_DODSNIPER_H
+#define WEAPON_DODSNIPER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "cbase.h"
+#include "shake.h"
+#include "weapon_dodsemiauto.h"
+#include "dod_shareddefs.h"
+
+#if defined( CLIENT_DLL )
+ #define CDODSniperWeapon C_DODSniperWeapon
+#endif
+
+#define DOD_SNIPER_ZOOM_CHANGE_TIME 0.3
+
+class CDODSniperWeapon : public CDODSemiAutoWeapon
+{
+public:
+ DECLARE_CLASS( CDODSniperWeapon, CDODSemiAutoWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+#ifndef CLIENT_DLL
+ DECLARE_DATADESC();
+#endif
+
+ CDODSniperWeapon();
+
+ virtual void Spawn( void );
+ virtual bool Holster( CBaseCombatWeapon *pSwitchingTo );
+ virtual bool Reload( void );
+ virtual void FinishReload( void );
+ virtual void Drop( const Vector &vecVelocity );
+ virtual void ItemPostFrame( void );
+
+ virtual void PrimaryAttack( void );
+ virtual void SecondaryAttack( void );
+
+ void ResetTimers( void ); // reset all the flags, timers that would cause us to re-zoom or unzoom
+
+#ifdef CLIENT_DLL
+ virtual Vector GetDesiredViewModelOffset( C_DODPlayer *pOwner );
+ virtual float GetViewModelSwayScale( void );
+
+ float GetZoomedPercentage( void );
+#endif
+
+ // Is the weapon completely zoomed, finished the raising animation
+ bool IsFullyZoomed( void );
+
+ virtual bool ShouldDrawCrosshair( void );
+
+ virtual bool HideViewModelWhenZoomed( void ) { return true; }
+
+ virtual float GetWeaponAccuracy( float flPlayerSpeed );
+
+ virtual float GetZoomedFOV( void ) { return 20; }
+
+ bool IsZoomed( void );
+
+ virtual bool ShouldZoomOutBetweenShots( void ) { return true; }
+ virtual bool ShouldRezoomAfterReload( void ) { return false; }
+
+ void ToggleZoom( void );
+
+ void ZoomIn( void );
+ void ZoomOut( void );
+
+ void ZoomOutIn( void );
+
+ void SetRezoom( bool bRezoom, float flDelay );
+
+ bool IsZoomingIn( void );
+
+ CNetworkVar( bool, m_bDoViewAnim );
+
+
+
+#ifdef CLIENT_DLL
+ bool m_bDoViewAnimCache;
+ float m_flViewAnimTimer;
+ float m_flZoomPercent;
+#endif
+
+protected:
+ bool m_bShouldRezoomAfterShot; // if the gun zooms out after a shot, does it zoom back in automatically?
+
+private:
+ CDODSniperWeapon( const CDODSniperWeapon & );
+
+ float m_flUnzoomTime;
+ float m_flRezoomTime;
+
+ float m_flZoomInTime;
+ float m_flZoomOutTime;
+
+ bool m_bRezoomAfterReload;
+ float m_flZoomChangeTime;
+ bool m_bRezoomAfterShot;
+};
+
+#endif // WEAPON_DODSNIPER_H \ No newline at end of file
diff --git a/game/shared/dod/weapon_explodinghandgrenade.cpp b/game/shared/dod/weapon_explodinghandgrenade.cpp
new file mode 100644
index 0000000..379f725
--- /dev/null
+++ b/game/shared/dod/weapon_explodinghandgrenade.cpp
@@ -0,0 +1,52 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasegrenade.h"
+
+#ifdef CLIENT_DLL
+ #define CWeaponExplodingHandGrenade C_WeaponExplodingHandGrenade
+#else
+ #include "dod_handgrenade.h" //the thing that we throw
+#endif
+
+
+class CWeaponExplodingHandGrenade : public CWeaponDODBaseGrenade
+{
+public:
+ DECLARE_CLASS( CWeaponExplodingHandGrenade, CWeaponDODBaseGrenade );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CWeaponExplodingHandGrenade() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_FRAG_US_LIVE; }
+
+#ifndef CLIENT_DLL
+
+ virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime = GRENADE_FUSE_LENGTH )
+ {
+ CDODHandGrenade::Create( vecSrc, vecAngles, vecVel, angImpulse, pPlayer, flLifeTime, GetWeaponID() );
+ }
+
+#endif
+
+ virtual bool IsArmed( void ) { return true; }
+
+private:
+ CWeaponExplodingHandGrenade( const CWeaponExplodingHandGrenade & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponExplodingHandGrenade, DT_WeaponExplodingHandGrenade )
+
+BEGIN_NETWORK_TABLE(CWeaponExplodingHandGrenade, DT_WeaponExplodingHandGrenade)
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponExplodingHandGrenade ) //MATTTODO: are these necessary?
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_frag_us_live, CWeaponExplodingHandGrenade );
+PRECACHE_WEAPON_REGISTER( weapon_frag_us_live ); \ No newline at end of file
diff --git a/game/shared/dod/weapon_explodingstickgrenade.cpp b/game/shared/dod/weapon_explodingstickgrenade.cpp
new file mode 100644
index 0000000..fa5e012
--- /dev/null
+++ b/game/shared/dod/weapon_explodingstickgrenade.cpp
@@ -0,0 +1,54 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasegrenade.h"
+
+#ifdef CLIENT_DLL
+ #define CWeaponExplodingStickGrenade C_WeaponExplodingStickGrenade
+#else
+ #include "dod_stickgrenade.h" //the thing that we throw
+#endif
+
+class CWeaponExplodingStickGrenade : public CWeaponDODBaseGrenade
+{
+public:
+ DECLARE_CLASS( CWeaponExplodingStickGrenade, CWeaponDODBaseGrenade );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CWeaponExplodingStickGrenade() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_FRAG_GER_LIVE; }
+
+#ifndef CLIENT_DLL
+
+ virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime = GRENADE_FUSE_LENGTH )
+ {
+ // align the stickgrenade vertically and spin end over end
+ QAngle vecNewAngles = QAngle(45,pPlayer->EyeAngles().y,0);
+ AngularImpulse angNewImpulse = AngularImpulse( 0, 600, 0 );
+
+ CDODStickGrenade::Create( vecSrc, vecNewAngles, vecVel, angNewImpulse, pPlayer, flLifeTime, GetWeaponID() );
+ }
+
+#endif
+
+ virtual bool IsArmed( void ) { return true; }
+
+ CWeaponExplodingStickGrenade( const CWeaponExplodingStickGrenade & ) {}
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponExplodingStickGrenade, DT_WeaponExplodingStickGrenade )
+
+BEGIN_NETWORK_TABLE(CWeaponExplodingStickGrenade, DT_WeaponExplodingStickGrenade)
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponExplodingStickGrenade ) //MATTTODO: are these necessary?
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_frag_ger_live, CWeaponExplodingStickGrenade );
+PRECACHE_WEAPON_REGISTER( weapon_frag_ger_live ); \ No newline at end of file
diff --git a/game/shared/dod/weapon_garand.cpp b/game/shared/dod/weapon_garand.cpp
new file mode 100644
index 0000000..7fb6ec0
--- /dev/null
+++ b/game/shared/dod/weapon_garand.cpp
@@ -0,0 +1,203 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodsniper.h"
+#include "dod_shareddefs.h"
+
+#ifndef CLIENT_DLL
+ #include "te_effect_dispatch.h"
+ #include "effect_dispatch_data.h"
+#endif
+
+#if defined( CLIENT_DLL )
+ #define CWeaponGarand C_WeaponGarand
+
+ #include "c_dod_player.h"
+#endif
+
+
+class CWeaponGarand : public CDODSniperWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponGarand, CDODSniperWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponGarand() {}
+
+ virtual void Spawn( void );
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_GARAND; }
+
+ // weapon id for stats purposes
+ virtual DODWeaponID GetStatsWeaponID( void )
+ {
+ if ( IsFullyZoomed() )
+ return WEAPON_GARAND_ZOOMED;
+ else
+ return WEAPON_GARAND;
+ }
+
+ virtual Activity GetIdleActivity( void );
+ virtual Activity GetPrimaryAttackActivity( void );
+ virtual Activity GetDrawActivity( void );
+
+ virtual void PrimaryAttack( void );
+ virtual bool Reload( void );
+
+ virtual float GetZoomedFOV( void ) { return 55; }
+
+ virtual bool HideViewModelWhenZoomed( void ) { return false; }
+
+ virtual bool ShouldZoomOutBetweenShots( void ) { return false; }
+ virtual bool ShouldRezoomAfterReload( void ) { return true; }
+
+ virtual float GetRecoil( void ) { return 4.0f; }
+
+private:
+ CWeaponGarand( const CWeaponGarand & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponGarand, DT_WeaponGarand )
+
+BEGIN_NETWORK_TABLE( CWeaponGarand, DT_WeaponGarand )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponGarand )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_garand, CWeaponGarand );
+PRECACHE_WEAPON_REGISTER( weapon_garand );
+
+void CWeaponGarand::Spawn( void )
+{
+ m_iAltFireHint = HINT_USE_IRON_SIGHTS;
+
+ BaseClass::Spawn();
+}
+
+acttable_t CWeaponGarand::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_RIFLE, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_RIFLE, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_RIFLE, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_RIFLE, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_RIFLE, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_RIFLE, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_RIFLE, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_RIFLE, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_RIFLE, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_RIFLE, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_RIFLE, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_RIFLE, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_RIFLE, false },
+
+ // Zoomed Aim
+ { ACT_DOD_IDLE_ZOOMED, ACT_DOD_STAND_ZOOM_RIFLE, false },
+ { ACT_DOD_CROUCH_ZOOMED, ACT_DOD_CROUCH_ZOOM_RIFLE, false },
+ { ACT_DOD_CROUCHWALK_ZOOMED, ACT_DOD_CROUCHWALK_ZOOM_RIFLE, false },
+ { ACT_DOD_WALK_ZOOMED, ACT_DOD_WALK_ZOOM_RIFLE, false },
+ { ACT_DOD_PRONE_ZOOMED, ACT_DOD_PRONE_ZOOM_RIFLE, false },
+ { ACT_DOD_PRONE_FORWARD_ZOOMED, ACT_DOD_PRONE_ZOOM_FORWARD_RIFLE, false },
+
+ // Attack ( prone? deployed? )
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_RIFLE, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_RIFLE, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_RIFLE, false },
+
+ { ACT_RELOAD, ACT_DOD_RELOAD_RIFLE, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_RIFLE, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_RIFLE, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_K98, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_K98, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponGarand );
+
+Activity CWeaponGarand::GetIdleActivity( void )
+{
+ Activity actIdle;
+
+ if( m_iClip1 <= 0 )
+ actIdle = ACT_VM_IDLE_EMPTY;
+ else
+ actIdle = ACT_VM_IDLE;
+
+ return actIdle;
+}
+
+Activity CWeaponGarand::GetPrimaryAttackActivity( void )
+{
+ Activity actPrim;
+
+ if ( IsFullyZoomed() )
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED;
+ else if( m_iClip1 <= 0 )
+ actPrim = ACT_VM_PRIMARYATTACK_EMPTY;
+ else
+ actPrim = ACT_VM_PRIMARYATTACK;
+
+ return actPrim;
+}
+
+Activity CWeaponGarand::GetDrawActivity( void )
+{
+ Activity actDraw;
+
+ if( m_iClip1 <= 0 )
+ actDraw = ACT_VM_DRAW_EMPTY;
+ else
+ actDraw = ACT_VM_DRAW;
+
+ return actDraw;
+}
+
+void CWeaponGarand::PrimaryAttack( void )
+{
+ int clip = m_iClip1;
+
+ BaseClass::PrimaryAttack();
+
+ // If we just fired our last bullet
+ if( clip != m_iClip1 && m_iClip1 == 0 )
+ {
+ // clip "DING!"
+ WeaponSound( SPECIAL1 );
+
+#ifndef CLIENT_DLL
+ CEffectData data;
+ data.m_nHitBox = EJECTBRASS_GARANDCLIP;
+ GetPlayerOwner()->GetAttachment( 2, data.m_vOrigin, data.m_vAngles );
+
+ // shoot it up in the air
+ data.m_vAngles.x = -90;
+ data.m_vAngles.y = 0;
+ data.m_vAngles.z = 0;
+
+ DispatchEffect( "DOD_EjectBrass", data );
+#endif
+ }
+}
+
+bool CWeaponGarand::Reload( void )
+{
+ if( m_iClip1 > 0 )
+ {
+#ifdef CLIENT_DLL
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+ Assert( pPlayer );
+ pPlayer->HintMessage( HINT_GARAND_RELOAD, true );
+#endif
+ return false;
+ }
+
+ return BaseClass::Reload();
+}
+
diff --git a/game/shared/dod/weapon_gerknife.cpp b/game/shared/dod/weapon_gerknife.cpp
new file mode 100644
index 0000000..1c8f4e7
--- /dev/null
+++ b/game/shared/dod/weapon_gerknife.cpp
@@ -0,0 +1,56 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasemelee.h"
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponGerKnife C_WeaponGerKnife
+
+#endif
+
+
+class CWeaponGerKnife : public CWeaponDODBaseMelee
+{
+public:
+ DECLARE_CLASS( CWeaponGerKnife, CWeaponDODBaseMelee );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponGerKnife() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_GERKNIFE; }
+
+private:
+ CWeaponGerKnife( const CWeaponGerKnife & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponGerKnife, DT_WeaponGerKnife )
+
+BEGIN_NETWORK_TABLE( CWeaponGerKnife, DT_WeaponGerKnife )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponGerKnife )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_gerknife, CWeaponGerKnife );
+PRECACHE_WEAPON_REGISTER( weapon_gerknife );
+
+acttable_t CWeaponGerKnife::m_acttable[] =
+{
+ { ACT_IDLE, ACT_DOD_STAND_AIM_KNIFE, false },
+ { ACT_CROUCHIDLE, ACT_DOD_CROUCH_AIM_KNIFE, false },
+ { ACT_RUN_CROUCH, ACT_DOD_CROUCHWALK_AIM_KNIFE, false },
+ { ACT_WALK, ACT_DOD_WALK_AIM_KNIFE, false },
+ { ACT_RUN, ACT_DOD_RUN_AIM_KNIFE, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_KNIFE, false },
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_KNIFE, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_KNIFE, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponGerKnife ); \ No newline at end of file
diff --git a/game/shared/dod/weapon_greasegun.cpp b/game/shared/dod/weapon_greasegun.cpp
new file mode 100644
index 0000000..db748f8
--- /dev/null
+++ b/game/shared/dod/weapon_greasegun.cpp
@@ -0,0 +1,64 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodfullauto.h"
+
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponGreaseGun C_WeaponGreaseGun
+
+#endif
+
+
+class CWeaponGreaseGun : public CDODFullAutoWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponGreaseGun, CDODFullAutoWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponGreaseGun() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_GREASEGUN; }
+
+private:
+ CWeaponGreaseGun( const CWeaponGreaseGun & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponGreaseGun, DT_WeaponGreaseGun )
+
+BEGIN_NETWORK_TABLE( CWeaponGreaseGun, DT_WeaponGreaseGun )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponGreaseGun )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_greasegun, CWeaponGreaseGun );
+PRECACHE_WEAPON_REGISTER( weapon_greasegun );
+
+acttable_t CWeaponGreaseGun::m_acttable[] =
+{
+ // Aim
+ { ACT_IDLE, ACT_DOD_STAND_AIM_GREASE, false },
+ { ACT_CROUCHIDLE, ACT_DOD_CROUCH_AIM_GREASE, false },
+ { ACT_RUN_CROUCH, ACT_DOD_CROUCHWALK_AIM_GREASE, false },
+ { ACT_WALK, ACT_DOD_WALK_AIM_GREASE, false },
+ { ACT_RUN, ACT_DOD_RUN_AIM_GREASE, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_GREASE, false },
+
+ // Attack ( prone? )
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_GREASE, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_GREASE, false },
+
+ // Reload ( prone? )
+ { ACT_RELOAD, ACT_DOD_RELOAD_GREASEGUN, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_GREASEGUN, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponGreaseGun ); \ No newline at end of file
diff --git a/game/shared/dod/weapon_handgrenade.cpp b/game/shared/dod/weapon_handgrenade.cpp
new file mode 100644
index 0000000..f3e17c4
--- /dev/null
+++ b/game/shared/dod/weapon_handgrenade.cpp
@@ -0,0 +1,49 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasegrenade.h"
+
+#ifdef CLIENT_DLL
+ #define CWeaponHandGrenade C_WeaponHandGrenade
+#else
+ #include "dod_handgrenade.h" //the thing that we throw
+#endif
+
+class CWeaponHandGrenade : public CWeaponDODBaseGrenade
+{
+public:
+ DECLARE_CLASS( CWeaponHandGrenade, CWeaponDODBaseGrenade );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CWeaponHandGrenade() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_FRAG_US; }
+
+#ifndef CLIENT_DLL
+
+ virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime = GRENADE_FUSE_LENGTH )
+ {
+ CDODHandGrenade::Create( vecSrc, vecAngles, vecVel, angImpulse, pPlayer, flLifeTime, GetWeaponID() );
+ }
+
+#endif
+
+private:
+ CWeaponHandGrenade( const CWeaponHandGrenade & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponHandGrenade, DT_WeaponHandGrenade )
+
+BEGIN_NETWORK_TABLE(CWeaponHandGrenade, DT_WeaponHandGrenade)
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponHandGrenade )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_frag_us, CWeaponHandGrenade );
+PRECACHE_WEAPON_REGISTER( weapon_frag_us ); \ No newline at end of file
diff --git a/game/shared/dod/weapon_k98.cpp b/game/shared/dod/weapon_k98.cpp
new file mode 100644
index 0000000..a279568
--- /dev/null
+++ b/game/shared/dod/weapon_k98.cpp
@@ -0,0 +1,140 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodsniper.h"
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponK98 C_WeaponK98
+
+#endif
+
+
+class CWeaponK98 : public CDODSniperWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponK98, CDODSniperWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponK98() {}
+
+ virtual void Spawn( void );
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_K98; }
+
+ // weapon id for stats purposes
+ virtual DODWeaponID GetStatsWeaponID( void )
+ {
+ if ( IsFullyZoomed() )
+ return WEAPON_K98_ZOOMED;
+ else
+ return WEAPON_K98;
+ }
+
+ virtual bool ShouldAutoEjectBrass( void ) { return false; }
+
+ virtual float GetZoomedFOV( void ) { return 55; }
+
+ virtual bool HideViewModelWhenZoomed( void ) { return false; }
+
+ virtual bool ShouldRezoomAfterReload( void ) { return true; }
+
+ virtual Activity GetPrimaryAttackActivity( void );
+
+ virtual float GetFireDelay( void );
+
+ virtual float GetRecoil( void ) { return 8.0f; }
+
+private:
+ CWeaponK98( const CWeaponK98 & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponK98, DT_WeaponK98 )
+
+BEGIN_NETWORK_TABLE( CWeaponK98, DT_WeaponK98 )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponK98 )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_k98, CWeaponK98 );
+PRECACHE_WEAPON_REGISTER( weapon_k98 );
+
+void CWeaponK98::Spawn( void )
+{
+ m_iAltFireHint = HINT_USE_IRON_SIGHTS;
+
+ BaseClass::Spawn();
+
+ m_bShouldRezoomAfterShot = false;
+}
+
+acttable_t CWeaponK98::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_BOLT, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_BOLT, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_BOLT, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_BOLT, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_BOLT, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_BOLT, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_BOLT, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_BOLT, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_BOLT, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_BOLT, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_BOLT, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_BOLT, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_BOLT, false },
+
+ // Zoomed Aim
+ { ACT_DOD_IDLE_ZOOMED, ACT_DOD_STAND_ZOOM_BOLT, false },
+ { ACT_DOD_CROUCH_ZOOMED, ACT_DOD_CROUCH_ZOOM_BOLT, false },
+ { ACT_DOD_CROUCHWALK_ZOOMED, ACT_DOD_CROUCHWALK_ZOOM_BOLT, false },
+ { ACT_DOD_WALK_ZOOMED, ACT_DOD_WALK_ZOOM_BOLT, false },
+ { ACT_DOD_PRONE_ZOOMED, ACT_DOD_PRONE_ZOOM_BOLT, false },
+ { ACT_DOD_PRONE_FORWARD_ZOOMED, ACT_DOD_PRONE_ZOOM_FORWARD_BOLT, false },
+
+ // Attack ( prone? )
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_BOLT, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_BOLT, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_BOLT, false },
+
+ // Reload ( prone ? )
+ { ACT_RELOAD, ACT_DOD_RELOAD_BOLT, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_BOLT, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_BOLT, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_K98, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_K98, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponK98 );
+
+Activity CWeaponK98::GetPrimaryAttackActivity( void )
+{
+ Activity actPrim;
+
+ if( m_iClip1 <= 0 )
+ actPrim = ACT_VM_PRIMARYATTACK_EMPTY;
+ else
+ actPrim = ACT_VM_PRIMARYATTACK;
+
+ return actPrim;
+}
+
+float CWeaponK98::GetFireDelay( void )
+{
+ if ( m_iClip1 <= 0 )
+ {
+ return SequenceDuration();
+ }
+
+ return BaseClass::GetFireDelay();
+}
+
diff --git a/game/shared/dod/weapon_k98_scoped.cpp b/game/shared/dod/weapon_k98_scoped.cpp
new file mode 100644
index 0000000..b3246f1
--- /dev/null
+++ b/game/shared/dod/weapon_k98_scoped.cpp
@@ -0,0 +1,156 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodsniper.h"
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponK98Scoped C_WeaponK98Scoped
+
+#endif
+
+
+class CWeaponK98Scoped : public CDODSniperWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponK98Scoped, CDODSniperWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponK98Scoped() {}
+
+ virtual void Spawn( void );
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_K98_SCOPED; }
+
+ // weapon id for stats purposes
+ virtual DODWeaponID GetStatsWeaponID( void )
+ {
+ if ( IsFullyZoomed() )
+ return WEAPON_K98_SCOPED_ZOOMED;
+ else
+ return WEAPON_K98_SCOPED;
+ }
+
+ virtual bool ShouldAutoEjectBrass( void ) { return false; }
+ virtual bool ShouldDrawCrosshair( void ) { return false; }
+
+ virtual bool ShouldDrawViewModel( void )
+ {
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+
+ Assert( pPlayer );
+
+ if ( !pPlayer )
+ return false;
+
+ if ( pPlayer->GetFOV() < 90 )
+ return false;
+
+ // handle case when we are spectating someone and don't know their fov
+ if ( IsFullyZoomed() )
+ return false;
+
+ return BaseClass::ShouldDrawViewModel();
+ }
+
+ virtual bool ShouldDrawMuzzleFlash( void )
+ {
+ return ShouldDrawViewModel();
+ }
+
+ virtual Activity GetPrimaryAttackActivity( void );
+
+ virtual float GetFireDelay( void );
+
+ virtual float GetRecoil( void ) { return 6.0f; }
+
+private:
+ CWeaponK98Scoped( const CWeaponK98Scoped & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponK98Scoped, DT_WeaponK98Scoped )
+
+BEGIN_NETWORK_TABLE( CWeaponK98Scoped, DT_WeaponK98Scoped )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponK98Scoped )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_k98_scoped, CWeaponK98Scoped );
+PRECACHE_WEAPON_REGISTER( weapon_k98_scoped );
+
+void CWeaponK98Scoped::Spawn( void )
+{
+ m_iAltFireHint = HINT_USE_ZOOM;
+
+ BaseClass::Spawn();
+}
+
+acttable_t CWeaponK98Scoped::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_BOLT, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_BOLT, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_BOLT, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_BOLT, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_BOLT, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_BOLT, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_BOLT, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_BOLT, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_BOLT, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_BOLT, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_BOLT, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_BOLT, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_BOLT, false },
+
+ // Zoomed Aim
+ { ACT_DOD_IDLE_ZOOMED, ACT_DOD_STAND_ZOOM_BOLT, false },
+ { ACT_DOD_CROUCH_ZOOMED, ACT_DOD_CROUCH_ZOOM_BOLT, false },
+ { ACT_DOD_CROUCHWALK_ZOOMED, ACT_DOD_CROUCHWALK_ZOOM_BOLT, false },
+ { ACT_DOD_WALK_ZOOMED, ACT_DOD_WALK_ZOOM_BOLT, false },
+ { ACT_DOD_PRONE_ZOOMED, ACT_DOD_PRONE_ZOOM_BOLT, false },
+ { ACT_DOD_PRONE_FORWARD_ZOOMED, ACT_DOD_PRONE_ZOOM_FORWARD_BOLT, false },
+
+ // Attack ( prone? )
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_BOLT, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_BOLT, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_BOLT, false },
+
+ // Reload ( prone ? )
+ { ACT_RELOAD, ACT_DOD_RELOAD_BOLT, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_BOLT, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_BOLT, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_K98, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_K98, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponK98Scoped );
+
+Activity CWeaponK98Scoped::GetPrimaryAttackActivity( void )
+{
+ Activity actPrim;
+
+ if( m_iClip1 <= 0 )
+ actPrim = ACT_VM_PRIMARYATTACK_EMPTY;
+ else
+ actPrim = ACT_VM_PRIMARYATTACK;
+
+ return actPrim;
+}
+
+float CWeaponK98Scoped::GetFireDelay( void )
+{
+ if ( m_iClip1 <= 0 )
+ {
+ return SequenceDuration();
+ }
+
+ return BaseClass::GetFireDelay();
+} \ No newline at end of file
diff --git a/game/shared/dod/weapon_m1carbine.cpp b/game/shared/dod/weapon_m1carbine.cpp
new file mode 100644
index 0000000..820d5a3
--- /dev/null
+++ b/game/shared/dod/weapon_m1carbine.cpp
@@ -0,0 +1,76 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodsemiauto.h"
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponM1Carbine C_WeaponM1Carbine
+
+#endif
+
+
+class CWeaponM1Carbine : public CDODSemiAutoWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponM1Carbine, CDODSemiAutoWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponM1Carbine() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_M1CARBINE; }
+
+ virtual float GetRecoil( void ) { return 1.4f; }
+
+private:
+ CWeaponM1Carbine( const CWeaponM1Carbine & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponM1Carbine, DT_WeaponM1Carbine )
+
+BEGIN_NETWORK_TABLE( CWeaponM1Carbine, DT_WeaponM1Carbine )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponM1Carbine )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_m1carbine, CWeaponM1Carbine );
+PRECACHE_WEAPON_REGISTER( weapon_m1carbine );
+
+acttable_t CWeaponM1Carbine::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_RIFLE, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_RIFLE, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_RIFLE, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_RIFLE, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_RIFLE, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_RIFLE, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_RIFLE, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_RIFLE, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_RIFLE, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_RIFLE, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_RIFLE, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_RIFLE, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_RIFLE, false },
+
+ // Attack ( prone? )
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_RIFLE, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_RIFLE, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_RIFLE, false },
+
+ { ACT_RELOAD, ACT_DOD_RELOAD_M1CARBINE, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_M1CARBINE, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_M1CARBINE, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_K98, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_K98, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponM1Carbine ); \ No newline at end of file
diff --git a/game/shared/dod/weapon_mg34.cpp b/game/shared/dod/weapon_mg34.cpp
new file mode 100644
index 0000000..3479485
--- /dev/null
+++ b/game/shared/dod/weapon_mg34.cpp
@@ -0,0 +1,207 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbipodgun.h"
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponMG34 C_WeaponMG34
+ #include "c_dod_player.h"
+
+#else
+
+ #include "dod_player.h"
+#endif
+
+
+class CWeaponMG34 : public CDODBipodWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponMG34, CDODBipodWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponMG34() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_MG34; }
+
+ virtual void PrimaryAttack( void );
+ virtual bool Reload( void );
+
+ Activity GetReloadActivity( void );
+ Activity GetDrawActivity( void );
+ Activity GetDeployActivity( void );
+ Activity GetUndeployActivity( void );
+ Activity GetIdleActivity( void );
+ Activity GetPrimaryAttackActivity( void );
+
+ virtual bool ShouldDrawCrosshair( void ) { return IsDeployed(); }
+
+private:
+ CWeaponMG34( const CWeaponMG34 & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponMG34, DT_WeaponMG34 )
+
+BEGIN_NETWORK_TABLE( CWeaponMG34, DT_WeaponMG34 )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponMG34 )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_mg34, CWeaponMG34 );
+PRECACHE_WEAPON_REGISTER( weapon_mg34 );
+
+acttable_t CWeaponMG34::m_acttable[] =
+{
+ // Aim
+ { ACT_IDLE, ACT_DOD_STAND_AIM_MG, false },
+ { ACT_CROUCHIDLE, ACT_DOD_CROUCH_AIM_MG, false },
+ { ACT_RUN_CROUCH, ACT_DOD_CROUCHWALK_AIM_MG, false },
+ { ACT_WALK, ACT_DOD_WALK_AIM_MG, false },
+ { ACT_RUN, ACT_DOD_RUN_AIM_MG, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_MG, false },
+
+ // Deployed Aim
+ { ACT_DOD_DEPLOYED, ACT_DOD_DEPLOY_MG, false },
+ { ACT_DOD_PRONE_DEPLOYED, ACT_DOD_PRONE_DEPLOY_MG, false },
+
+ // Attack ( prone? deployed? )
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_MG, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_MG, false },
+ { ACT_DOD_PRIMARYATTACK_DEPLOYED, ACT_DOD_PRIMARYATTACK_DEPLOYED_MG, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED, ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED_MG,false },
+
+ // Reload ( prone? deployed? )
+ { ACT_DOD_RELOAD_DEPLOYED, ACT_DOD_RELOAD_DEPLOYED_MG34, false },
+ { ACT_DOD_RELOAD_PRONE_DEPLOYED, ACT_DOD_RELOAD_PRONE_DEPLOYED_MG34, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponMG34 );
+
+void CWeaponMG34::PrimaryAttack( void )
+{
+#ifdef CLIENT_DLL
+ C_DODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+#else
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+#endif
+
+ Assert( pPlayer );
+
+ if( !IsDeployed() )
+ {
+#ifdef CLIENT_DLL
+ pPlayer->HintMessage( HINT_MG_FIRE_UNDEPLOYED );
+#endif
+ pPlayer->m_Shared.SetSlowedTime( 0.2 );
+
+ float flStamina = pPlayer->m_Shared.GetStamina();
+
+ pPlayer->m_Shared.SetStamina( flStamina - 15 );
+ }
+
+ BaseClass::PrimaryAttack();
+}
+
+bool CWeaponMG34::Reload( void )
+{
+ if( !IsDeployed() )
+ {
+ ClientPrint( GetPlayerOwner(), HUD_PRINTCENTER, "#Dod_mg_reload" );
+ return false;
+ }
+
+ return BaseClass::Reload();
+}
+
+Activity CWeaponMG34::GetReloadActivity( void )
+{
+ return ACT_VM_RELOAD;
+}
+
+Activity CWeaponMG34::GetDrawActivity( void )
+{
+ Activity actDraw;
+
+ if( m_iClip1 <= 0 )
+ actDraw = ACT_VM_DRAW_EMPTY;
+ else
+ actDraw = ACT_VM_DRAW;
+
+ return actDraw;
+}
+
+Activity CWeaponMG34::GetDeployActivity( void )
+{
+ Activity actDeploy;
+
+ if( m_iClip1 <= 0 )
+ actDeploy = ACT_VM_DEPLOY_EMPTY;
+ else
+ actDeploy = ACT_VM_DEPLOY;
+
+ return actDeploy;
+}
+
+Activity CWeaponMG34::GetUndeployActivity( void )
+{
+ Activity actUndeploy;
+
+ if( m_iClip1 <= 0 )
+ actUndeploy = ACT_VM_UNDEPLOY_EMPTY;
+ else
+ actUndeploy = ACT_VM_UNDEPLOY;
+
+ return actUndeploy;
+}
+
+Activity CWeaponMG34::GetIdleActivity( void )
+{
+ Activity actIdle;
+
+ if( IsDeployed() )
+ {
+ if( m_iClip1 <= 0 )
+ actIdle = ACT_VM_IDLE_DEPLOYED_EMPTY;
+ else
+ actIdle = ACT_VM_IDLE_DEPLOYED;
+ }
+ else
+ {
+ if( m_iClip1 <= 0 )
+ actIdle = ACT_VM_IDLE_EMPTY;
+ else
+ actIdle = ACT_VM_IDLE;
+ }
+
+ return actIdle;
+}
+
+Activity CWeaponMG34::GetPrimaryAttackActivity( void )
+{
+ Activity actPrim;
+
+ if( IsDeployed() )
+ {
+ if( m_iClip1 <= 0 )
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_EMPTY;
+ else
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED;
+ }
+ else
+ {
+ if( m_iClip1 <= 0 )
+ actPrim = ACT_VM_PRIMARYATTACK_EMPTY;
+ else
+ actPrim = ACT_VM_PRIMARYATTACK;
+ }
+
+ return actPrim;
+}
+
diff --git a/game/shared/dod/weapon_mg42.cpp b/game/shared/dod/weapon_mg42.cpp
new file mode 100644
index 0000000..7321476
--- /dev/null
+++ b/game/shared/dod/weapon_mg42.cpp
@@ -0,0 +1,843 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_mg42.h"
+#include "engine/ivdebugoverlay.h"
+
+#if defined( CLIENT_DLL )
+
+ #include "tier1/KeyValues.h"
+ #include "particles_simple.h"
+ #include "particles_localspace.h"
+ #include "fx.h"
+ #include "c_dod_player.h"
+
+#else
+
+ #include "dod_player.h"
+
+#endif
+
+
+#ifdef CLIENT_DLL
+void ToolFramework_PostToolMessage( HTOOLHANDLE hEntity, KeyValues *msg );
+#endif
+
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponMG42, DT_WeaponMG42 )
+
+#ifdef GAME_DLL
+
+BEGIN_DATADESC( CWeaponMG42 )
+ DEFINE_THINKFUNC( CoolThink ),
+END_DATADESC()
+
+#endif
+
+BEGIN_NETWORK_TABLE( CWeaponMG42, DT_WeaponMG42 )
+#ifdef CLIENT_DLL
+ RecvPropInt ( RECVINFO( m_iWeaponHeat ) ),
+ RecvPropTime ( RECVINFO( m_flNextCoolTime ) ),
+ RecvPropBool ( RECVINFO( m_bOverheated ) ),
+#else
+ SendPropInt ( SENDINFO( m_iWeaponHeat ), 7, SPROP_UNSIGNED ),
+ SendPropFloat ( SENDINFO( m_flNextCoolTime ) ),
+ SendPropBool ( SENDINFO( m_bOverheated ) ),
+#endif
+END_NETWORK_TABLE()
+
+#ifdef CLIENT_DLL
+BEGIN_PREDICTION_DATA( CWeaponMG42 )
+ DEFINE_PRED_FIELD( m_iWeaponHeat, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD_TOL( m_flNextCoolTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
+ DEFINE_PRED_FIELD( m_bOverheated, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+END_PREDICTION_DATA()
+#endif
+
+LINK_ENTITY_TO_CLASS( weapon_mg42, CWeaponMG42 );
+PRECACHE_WEAPON_REGISTER( weapon_mg42 );
+
+acttable_t CWeaponMG42::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_MG, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_MG, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_MG, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_MG, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_MG, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_MG, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_MG, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_MG, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_MG, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_MG, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_MG, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_MG, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_MG, false },
+
+ // Deployed Aim
+ { ACT_DOD_DEPLOYED, ACT_DOD_DEPLOY_MG, false },
+ { ACT_DOD_PRONE_DEPLOYED, ACT_DOD_PRONE_DEPLOY_MG, false },
+
+ // Attack ( prone? deployed? )
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_MG, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_MG, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_MG, false },
+ { ACT_DOD_PRIMARYATTACK_DEPLOYED, ACT_DOD_PRIMARYATTACK_DEPLOYED_MG, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED, ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED_MG,false },
+
+ // Reload ( prone? deployed? )
+ { ACT_DOD_RELOAD_DEPLOYED, ACT_DOD_RELOAD_DEPLOYED_MG, false },
+ { ACT_DOD_RELOAD_PRONE_DEPLOYED, ACT_DOD_RELOAD_PRONE_DEPLOYED_MG, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_MG42, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_MG42, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponMG42 );
+
+void CWeaponMG42::Spawn( void )
+{
+ m_iWeaponHeat = 0;
+ m_flNextCoolTime = 0;
+
+ m_bOverheated = false;
+
+#ifdef CLIENT_DLL
+ m_pEmitter = NULL;
+ m_flParticleAccumulator = 0.0;
+ m_hParticleMaterial = ParticleMgr()->GetPMaterial( "sprites/effects/bazookapuff" );
+#endif
+
+ BaseClass::Spawn();
+}
+
+#ifdef CLIENT_DLL
+
+ CWeaponMG42::~CWeaponMG42()
+ {
+ if ( clienttools->IsInRecordingMode() && m_pEmitter.IsValid() && m_pEmitter->GetToolParticleEffectId() != TOOLPARTICLESYSTEMID_INVALID )
+ {
+ KeyValues *msg = new KeyValues( "ParticleSystem_ActivateEmitter" );
+ msg->SetInt( "id", m_pEmitter->GetToolParticleEffectId() );
+ msg->SetFloat( "time", gpGlobals->curtime );
+ msg->SetInt( "active", 0 );
+
+ msg->SetInt( "emitter", 0 );
+ ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
+
+ msg->SetInt( "emitter", 1 );
+ ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
+
+ msg->SetInt( "emitter", 2 );
+ ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
+
+ msg->SetInt( "emitter", 3 );
+ ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
+
+ msg->deleteThis();
+ }
+ }
+
+ void CWeaponMG42::OnDataChanged( DataUpdateType_t updateType )
+ {
+ BaseClass::OnDataChanged( updateType );
+
+ // BUG! This can happen more than once!
+ if ( updateType == DATA_UPDATE_CREATED )
+ {
+ if ( !m_pEmitter.IsValid() )
+ {
+ m_pEmitter = CSimpleEmitter::Create( "MGOverheat" );
+ }
+
+ Assert( m_pEmitter.IsValid() );
+ }
+
+ ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_ALWAYS );
+ }
+
+ // Client Think emits smoke particles based on heat
+ // ( except if we are holstered )
+ void CWeaponMG42::ClientThink( void )
+ {
+ m_pEmitter->SetSortOrigin( GetAbsOrigin() );
+
+ float flEmitRate = 0.0; //particles per second
+
+ // Only smoke if we are dropped ( no owner ) or if we have an owner and are active
+ if ( GetOwner() == NULL || GetOwner()->GetActiveWeapon() == this )
+ {
+ if ( m_iWeaponHeat > 85 )
+ {
+ flEmitRate = 30;
+ }
+ else if ( m_iWeaponHeat > 80 )
+ {
+ flEmitRate = 20;
+ }
+ else if ( m_iWeaponHeat > 65 )
+ {
+ flEmitRate = 10;
+ }
+ else if ( m_iWeaponHeat > 50 )
+ {
+ flEmitRate = 5;
+ }
+ }
+
+ m_flParticleAccumulator += ( gpGlobals->frametime * flEmitRate );
+
+ while( m_flParticleAccumulator > 0.0 )
+ {
+ EmitSmokeParticle();
+
+ m_flParticleAccumulator -= 1.0;
+ }
+ }
+
+ void CWeaponMG42::EmitSmokeParticle( void )
+ {
+ Vector vFront, vBack;
+ QAngle angles;
+
+ C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
+
+ bool bViewModel = false;
+
+ // if this is locally owned
+ if ( GetPlayerOwner() == pLocalPlayer )
+ {
+ C_BaseViewModel *vm = pLocalPlayer->GetViewModel( 0 );
+
+ if ( !vm )
+ return;
+
+ vm->GetAttachment( 1, vFront, angles );
+ vm->GetAttachment( 2, vBack, angles );
+
+ bViewModel = true;
+ }
+ else
+ {
+ // could be dropped, or held by another player
+ GetAttachment( 1, vFront, angles );
+ GetAttachment( 2, vBack, angles );
+ }
+
+ // Get a position somewhere on the barrel
+ Vector vPos = vBack + random->RandomFloat(0.0, 1.0 ) * ( vFront - vBack );
+
+ SimpleParticle *pParticle = m_pEmitter->AddSimpleParticle( m_hParticleMaterial, vPos );
+ if ( pParticle )
+ {
+ pParticle->m_vecVelocity = Vector( 0,0,12 );
+ pParticle->m_flRoll = random->RandomFloat( 0, 0.5 );
+ pParticle->m_flRollDelta = ( random->RandomInt(0,1) == 0 ? 1 : -1 ) * random->RandomFloat( 0.5, 1.0 );
+ pParticle->m_flDieTime = 1.8f;
+ pParticle->m_flLifetime = 0;
+ pParticle->m_uchColor[0] = 200;
+ pParticle->m_uchColor[1] = 200;
+ pParticle->m_uchColor[2] = 200;
+ pParticle->m_uchStartAlpha = 60;
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_uchStartSize = 4;
+ pParticle->m_uchEndSize = 25;
+ pParticle->m_iFlags = 0; //bViewModel ? FLE_VIEWMODEL : 0;
+ }
+ }
+
+#else
+
+ // This function does the cooling when the weapon is dropped or holstered
+ // regular, predicted cooling is done in ItemPostFrame
+ void CWeaponMG42::CoolThink( void )
+ {
+ if ( m_iWeaponHeat > 0 )
+ m_iWeaponHeat--;
+
+ SetContextThink( &CWeaponMG42::CoolThink, gpGlobals->curtime + 0.1, COOL_CONTEXT );
+ }
+
+#endif
+
+void CWeaponMG42::Precache()
+{
+ PrecacheMaterial( "sprites/effects/bazookapuff" );
+
+ PrecacheScriptSound( "Weapon_Mg42.OverHeat" );
+
+ BaseClass::Precache();
+}
+
+bool CWeaponMG42::Reload( void )
+{
+ if( !IsDeployed() )
+ {
+#ifdef CLIENT_DLL
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+ if ( pPlayer )
+ pPlayer->HintMessage( HINT_MG_DEPLOY_TO_RELOAD );
+#endif
+ return false;
+ }
+
+ return BaseClass::Reload();
+}
+
+void CWeaponMG42::FinishReload( void )
+{
+ BaseClass::FinishReload();
+
+ //Reset the heat when you complete a reload
+ m_iWeaponHeat = 0;
+}
+
+void CWeaponMG42::PrimaryAttack( void )
+{
+ if( m_bOverheated )
+ {
+ return;
+ }
+
+ if ( m_iClip1 <= 0 )
+ {
+ if (m_bFireOnEmpty)
+ {
+ PlayEmptySound();
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
+ }
+
+ return;
+ }
+
+
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+ Assert( pPlayer );
+
+ if( m_iWeaponHeat >= 99 )
+ {
+ //can't fire anymore, wait until heat is below 80
+#ifdef CLIENT_DLL
+ pPlayer->HintMessage( HINT_WEAPON_OVERHEAT );
+#endif
+ m_bOverheated = true;
+ m_bInAttack = true;
+
+ EmitSound( "Weapon_Mg42.OverHeat" );
+ return;
+ }
+
+ m_iWeaponHeat += 1; //2;
+ m_flNextCoolTime = gpGlobals->curtime + 0.16f;
+
+ if( !IsDeployed() )
+ {
+#ifdef CLIENT_DLL
+ pPlayer->HintMessage( HINT_MG_FIRE_UNDEPLOYED );
+#endif
+ pPlayer->m_Shared.SetSlowedTime( 0.2 );
+
+ float flStamina = pPlayer->m_Shared.GetStamina();
+
+ pPlayer->m_Shared.SetStamina( flStamina - 15 );
+ }
+
+ BaseClass::PrimaryAttack();
+}
+
+void CWeaponMG42::ItemPostFrame( void )
+{
+ ItemFrameCool();
+
+ if( m_iWeaponHeat < 80 )
+ m_bOverheated = false;
+
+ BaseClass::ItemPostFrame();
+}
+
+void CWeaponMG42::ItemBusyFrame( void )
+{
+ ItemFrameCool();
+
+ BaseClass::ItemBusyFrame();
+}
+
+void CWeaponMG42::ItemFrameCool( void )
+{
+ if( gpGlobals->curtime > m_flNextCoolTime )
+ {
+ if ( m_iWeaponHeat > 0 )
+ m_iWeaponHeat--;
+
+ m_flNextCoolTime = gpGlobals->curtime + 0.16f;
+ }
+}
+
+bool CWeaponMG42::Deploy( void )
+{
+ // stop the fake cooling when we deploy the weapon
+ SetContextThink( NULL, 0.0, COOL_CONTEXT );
+
+ return BaseClass::Deploy();
+}
+
+bool CWeaponMG42::Holster( CBaseCombatWeapon *pSwitchingTo )
+{
+#ifndef CLIENT_DLL
+ SetContextThink( &CWeaponMG42::CoolThink, gpGlobals->curtime + 0.1, COOL_CONTEXT );
+#endif
+
+ return BaseClass::Holster(pSwitchingTo);
+}
+
+void CWeaponMG42::Drop( const Vector &vecVelocity )
+{
+#ifndef CLIENT_DLL
+ SetContextThink( &CWeaponMG42::CoolThink, gpGlobals->curtime + 0.1, COOL_CONTEXT );
+#endif
+
+ BaseClass::Drop( vecVelocity );
+}
+
+Activity CWeaponMG42::GetReloadActivity( void )
+{
+ return ACT_VM_RELOAD;
+}
+
+Activity CWeaponMG42::GetDrawActivity( void )
+{
+ Activity actDraw;
+
+ if( 0 && m_iClip1 <= 0 )
+ actDraw = ACT_VM_DRAW_EMPTY;
+ else
+ actDraw = ACT_VM_DRAW;
+
+ return actDraw;
+}
+
+Activity CWeaponMG42::GetDeployActivity( void )
+{
+ Activity actDeploy;
+
+ switch ( m_iClip1 )
+ {
+ case 8:
+ actDeploy = ACT_VM_DEPLOY_8;
+ break;
+ case 7:
+ actDeploy = ACT_VM_DEPLOY_7;
+ break;
+ case 6:
+ actDeploy = ACT_VM_DEPLOY_6;
+ break;
+ case 5:
+ actDeploy = ACT_VM_DEPLOY_5;
+ break;
+ case 4:
+ actDeploy = ACT_VM_DEPLOY_4;
+ break;
+ case 3:
+ actDeploy = ACT_VM_DEPLOY_3;
+ break;
+ case 2:
+ actDeploy = ACT_VM_DEPLOY_2;
+ break;
+ case 1:
+ actDeploy = ACT_VM_DEPLOY_1;
+ break;
+ case 0:
+ actDeploy = ACT_VM_DEPLOY_EMPTY;
+ break;
+ default:
+ actDeploy = ACT_VM_DEPLOY;
+ break;
+ }
+
+ return actDeploy;
+}
+
+Activity CWeaponMG42::GetUndeployActivity( void )
+{
+ Activity actUndeploy;
+
+ switch ( m_iClip1 )
+ {
+ case 8:
+ actUndeploy = ACT_VM_UNDEPLOY_8;
+ break;
+ case 7:
+ actUndeploy = ACT_VM_UNDEPLOY_7;
+ break;
+ case 6:
+ actUndeploy = ACT_VM_UNDEPLOY_6;
+ break;
+ case 5:
+ actUndeploy = ACT_VM_UNDEPLOY_5;
+ break;
+ case 4:
+ actUndeploy = ACT_VM_UNDEPLOY_4;
+ break;
+ case 3:
+ actUndeploy = ACT_VM_UNDEPLOY_3;
+ break;
+ case 2:
+ actUndeploy = ACT_VM_UNDEPLOY_2;
+ break;
+ case 1:
+ actUndeploy = ACT_VM_UNDEPLOY_1;
+ break;
+ case 0:
+ actUndeploy = ACT_VM_UNDEPLOY_EMPTY;
+ break;
+ default:
+ actUndeploy = ACT_VM_UNDEPLOY;
+ break;
+ }
+
+ return actUndeploy;
+}
+
+Activity CWeaponMG42::GetIdleActivity( void )
+{
+ Activity actIdle;
+
+ if( IsDeployed() )
+ {
+ switch ( m_iClip1 )
+ {
+ case 8:
+ actIdle = ACT_VM_IDLE_DEPLOYED_8;
+ break;
+ case 7:
+ actIdle = ACT_VM_IDLE_DEPLOYED_7;
+ break;
+ case 6:
+ actIdle = ACT_VM_IDLE_DEPLOYED_6;
+ break;
+ case 5:
+ actIdle = ACT_VM_IDLE_DEPLOYED_5;
+ break;
+ case 4:
+ actIdle = ACT_VM_IDLE_DEPLOYED_4;
+ break;
+ case 3:
+ actIdle = ACT_VM_IDLE_DEPLOYED_3;
+ break;
+ case 2:
+ actIdle = ACT_VM_IDLE_DEPLOYED_2;
+ break;
+ case 1:
+ actIdle = ACT_VM_IDLE_DEPLOYED_1;
+ break;
+ case 0:
+ actIdle = ACT_VM_IDLE_DEPLOYED_EMPTY;
+ break;
+ default:
+ actIdle = ACT_VM_IDLE_DEPLOYED;
+ break;
+ }
+ }
+ else
+ {
+ switch ( m_iClip1 )
+ {
+ case 8:
+ actIdle = ACT_VM_IDLE_8;
+ break;
+ case 7:
+ actIdle = ACT_VM_IDLE_7;
+ break;
+ case 6:
+ actIdle = ACT_VM_IDLE_6;
+ break;
+ case 5:
+ actIdle = ACT_VM_IDLE_5;
+ break;
+ case 4:
+ actIdle = ACT_VM_IDLE_4;
+ break;
+ case 3:
+ actIdle = ACT_VM_IDLE_3;
+ break;
+ case 2:
+ actIdle = ACT_VM_IDLE_2;
+ break;
+ case 1:
+ actIdle = ACT_VM_IDLE_1;
+ break;
+ case 0:
+ actIdle = ACT_VM_IDLE_EMPTY;
+ break;
+ default:
+ actIdle = ACT_VM_IDLE;
+ break;
+ }
+ }
+
+ return actIdle;
+}
+
+Activity CWeaponMG42::GetPrimaryAttackActivity( void )
+{
+ Activity actPrim;
+
+ if( IsDeployed() )
+ {
+ switch ( m_iClip1 )
+ {
+ case 8:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_8;
+ break;
+ case 7:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_7;
+ break;
+ case 6:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_6;
+ break;
+ case 5:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_5;
+ break;
+ case 4:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_4;
+ break;
+ case 3:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_3;
+ break;
+ case 2:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_2;
+ break;
+ case 1:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_1;
+ break;
+ case 0:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_EMPTY;
+ break;
+ default:
+ actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED;
+ break;
+ }
+ }
+ else
+ {
+ switch ( m_iClip1 )
+ {
+ case 8:
+ actPrim = ACT_VM_PRIMARYATTACK_8;
+ break;
+ case 7:
+ actPrim = ACT_VM_PRIMARYATTACK_7;
+ break;
+ case 6:
+ actPrim = ACT_VM_PRIMARYATTACK_6;
+ break;
+ case 5:
+ actPrim = ACT_VM_PRIMARYATTACK_5;
+ break;
+ case 4:
+ actPrim = ACT_VM_PRIMARYATTACK_4;
+ break;
+ case 3:
+ actPrim = ACT_VM_PRIMARYATTACK_3;
+ break;
+ case 2:
+ actPrim = ACT_VM_PRIMARYATTACK_2;
+ break;
+ case 1:
+ actPrim = ACT_VM_PRIMARYATTACK_1;
+ break;
+ case 0:
+ actPrim = ACT_VM_PRIMARYATTACK_EMPTY;
+ break;
+ default:
+ actPrim = ACT_VM_PRIMARYATTACK;
+ break;
+ }
+ }
+
+ return actPrim;
+}
+
+float CWeaponMG42::GetRecoil( void )
+{
+ CDODPlayer *p = ToDODPlayer( GetPlayerOwner() );
+
+ if( p && p->m_Shared.IsInMGDeploy() )
+ {
+ return 0.0f;
+ }
+
+ return 20;
+}
+
+#ifdef CLIENT_DLL
+
+//-----------------------------------------------------------------------------
+// This is called after sending this entity's recording state
+//-----------------------------------------------------------------------------
+void CWeaponMG42::CleanupToolRecordingState( KeyValues *msg )
+{
+ BaseClass::CleanupToolRecordingState( msg );
+
+ // Generally, this is used to allow the entity to clean up
+ // allocated state it put into the message, but here we're going
+ // to use it to send particle system messages because we
+ // know the smoke has been recorded at this point
+ if ( !clienttools->IsInRecordingMode() || !m_pEmitter.IsValid() )
+ return;
+
+ // NOTE: Particle system destruction message will be sent by the particle effect itself.
+ if ( m_pEmitter->GetToolParticleEffectId() == TOOLPARTICLESYSTEMID_INVALID )
+ {
+ int nId = m_pEmitter->AllocateToolParticleEffectId();
+
+ KeyValues *msg = new KeyValues( "ParticleSystem_Create" );
+ msg->SetString( "name", "CWeaponMG42 smoke" );
+ msg->SetInt( "id", nId );
+ msg->SetFloat( "time", gpGlobals->curtime );
+
+ KeyValues *pEmitter0 = msg->FindKey( "DmeSpriteEmitter", true );
+ pEmitter0->SetInt( "count", 5 ); // particles per second, when duration is < 0
+ pEmitter0->SetFloat( "duration", -1 );
+ pEmitter0->SetString( "material", "sprites/effects/bazookapuff" );
+ pEmitter0->SetInt( "active", 0 );
+
+ KeyValues *pInitializers = pEmitter0->FindKey( "initializers", true );
+
+ KeyValues *pPosition = pInitializers->FindKey( "DmeRandomAttachmentPositionEntityInitializer", true );
+ pPosition->SetPtr( "entindex", (void*)entindex() );
+ pPosition->SetInt( "attachmentIndex0", 1 );
+ pPosition->SetInt( "attachmentIndex1", 2 );
+
+ KeyValues *pLifetime = pInitializers->FindKey( "DmeRandomLifetimeInitializer", true );
+ pLifetime->SetFloat( "minLifetime", 1.8f );
+ pLifetime->SetFloat( "maxLifetime", 1.8f );
+
+ KeyValues *pVelocity = pInitializers->FindKey( "DmeConstantVelocityInitializer", true );
+ pVelocity->SetFloat( "velocityX", 0.0f );
+ pVelocity->SetFloat( "velocityY", 0.0f );
+ pVelocity->SetFloat( "velocityZ", 12.0f );
+
+ KeyValues *pRoll = pInitializers->FindKey( "DmeRandomRollInitializer", true );
+ pRoll->SetFloat( "minRoll", 0.0f );
+ pRoll->SetFloat( "maxRoll", 0.5f );
+
+ KeyValues *pRollSpeed = pInitializers->FindKey( "DmeSplitRandomRollSpeedInitializer", true );
+ pRollSpeed->SetFloat( "minRollSpeed", 0.5f );
+ pRollSpeed->SetFloat( "maxRollSpeed", 1.0f );
+
+ KeyValues *pColor = pInitializers->FindKey( "DmeRandomInterpolatedColorInitializer", true );
+ pColor->SetColor( "color1", Color( 200, 200, 200, 255 ) );
+ pColor->SetColor( "color2", Color( 200, 200, 200, 255 ) );
+
+ KeyValues *pAlpha = pInitializers->FindKey( "DmeRandomAlphaInitializer", true );
+ pAlpha->SetInt( "minStartAlpha", 60 );
+ pAlpha->SetInt( "maxStartAlpha", 60 );
+ pAlpha->SetInt( "minEndAlpha", 0 );
+ pAlpha->SetInt( "maxEndAlpha", 0 );
+
+ KeyValues *pSize = pInitializers->FindKey( "DmeRandomSizeInitializer", true );
+ pSize->SetFloat( "minStartSize", 4 );
+ pSize->SetFloat( "maxStartSize", 4 );
+ pSize->SetFloat( "minEndSize", 25 );
+ pSize->SetFloat( "maxEndSize", 25 );
+
+ KeyValues *pUpdaters = pEmitter0->FindKey( "updaters", true );
+
+ pUpdaters->FindKey( "DmePositionVelocityUpdater", true );
+ pUpdaters->FindKey( "DmeRollUpdater", true );
+ pUpdaters->FindKey( "DmeAlphaLinearUpdater", true );
+ pUpdaters->FindKey( "DmeSizeUpdater", true );
+
+ // create emitters for each emission rate: 5,10,20,30
+ KeyValues *pEmitter1 = pEmitter0->MakeCopy();
+ pEmitter1->SetInt( "count", 10 );
+ msg->AddSubKey( pEmitter1 );
+
+ KeyValues *pEmitter2 = pEmitter0->MakeCopy();
+ pEmitter2->SetInt( "count", 20 );
+ msg->AddSubKey( pEmitter2 );
+
+ KeyValues *pEmitter3 = pEmitter0->MakeCopy();
+ pEmitter3->SetInt( "count", 30 );
+ msg->AddSubKey( pEmitter3 );
+
+ // mark only the appropriate emitter active
+ bool bHolstered = GetOwner() && GetOwner()->GetActiveWeapon() != this;
+ if ( !bHolstered )
+ {
+ if ( m_iWeaponHeat > 85 )
+ {
+ pEmitter3->SetInt( "active", 1 );
+ }
+ else if ( m_iWeaponHeat > 80 )
+ {
+ pEmitter2->SetInt( "active", 1 );
+ }
+ else if ( m_iWeaponHeat > 65 )
+ {
+ pEmitter1->SetInt( "active", 1 );
+ }
+ else if ( m_iWeaponHeat > 50 )
+ {
+ pEmitter0->SetInt( "active", 1 );
+ }
+ }
+
+ ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
+ msg->deleteThis();
+ }
+ else
+ {
+ int nEmitterIndex = -1;
+ bool bHolstered = GetOwner() && GetOwner()->GetActiveWeapon() != this;
+ if ( !bHolstered )
+ {
+ if ( m_iWeaponHeat > 85 )
+ {
+ nEmitterIndex = 3;
+ }
+ else if ( m_iWeaponHeat > 80 )
+ {
+ nEmitterIndex = 2;
+ }
+ else if ( m_iWeaponHeat > 65 )
+ {
+ nEmitterIndex = 1;
+ }
+ else if ( m_iWeaponHeat > 50 )
+ {
+ nEmitterIndex = 0;
+ }
+ }
+
+ KeyValues *msg = new KeyValues( "ParticleSystem_ActivateEmitter" );
+ msg->SetInt( "id", m_pEmitter->GetToolParticleEffectId() );
+ msg->SetFloat( "time", gpGlobals->curtime );
+
+ msg->SetInt( "emitter", 0 );
+ msg->SetInt( "active", nEmitterIndex == 0 );
+ ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
+
+ msg->SetInt( "emitter", 1 );
+ msg->SetInt( "active", nEmitterIndex == 1 );
+ ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
+
+ msg->SetInt( "emitter", 2 );
+ msg->SetInt( "active", nEmitterIndex == 2 );
+ ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
+
+ msg->SetInt( "emitter", 3 );
+ msg->SetInt( "active", nEmitterIndex == 3 );
+ ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
+
+ msg->deleteThis();
+ }
+}
+
+#endif
diff --git a/game/shared/dod/weapon_mg42.h b/game/shared/dod/weapon_mg42.h
new file mode 100644
index 0000000..1efe467
--- /dev/null
+++ b/game/shared/dod/weapon_mg42.h
@@ -0,0 +1,108 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WEAPON_MG42_H
+#define WEAPON_MG42_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "weapon_dodbase.h"
+#include "weapon_dodbipodgun.h"
+
+#if defined( CLIENT_DLL )
+ #define CWeaponMG42 C_WeaponMG42
+#endif
+
+
+#define COOL_CONTEXT "CoolContext"
+
+class CWeaponMG42 : public CDODBipodWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponMG42, CDODBipodWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+#ifdef GAME_DLL
+ DECLARE_DATADESC();
+#endif
+
+ CWeaponMG42() {}
+#ifdef CLIENT_DLL
+ virtual ~CWeaponMG42();
+#endif
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_MG42; }
+
+ // weapon id for stats purposes
+ virtual DODWeaponID GetStatsWeaponID( void )
+ {
+ if ( !IsDeployed() )
+ return WEAPON_MG42_UNDEPLOYED;
+ else
+ return WEAPON_MG42;
+ }
+
+ virtual void Spawn();
+ virtual void Precache();
+ virtual void PrimaryAttack( void );
+ virtual bool Reload( void );
+ virtual void FinishReload( void );
+ virtual void ItemPostFrame( void );
+ virtual void ItemBusyFrame( void );
+ void ItemFrameCool( void );
+ virtual bool Deploy( void );
+ virtual bool Holster( CBaseCombatWeapon *pSwitchingTo );
+ virtual void Drop( const Vector &vecVelocity );
+
+ virtual Activity GetReloadActivity( void );
+ virtual Activity GetDrawActivity( void );
+ virtual Activity GetDeployActivity( void );
+ virtual Activity GetUndeployActivity( void );
+ virtual Activity GetIdleActivity( void );
+ virtual Activity GetPrimaryAttackActivity( void );
+
+ int GetWeaponHeat( void ) { return m_iWeaponHeat; }
+
+ virtual bool ShouldDrawCrosshair( void ) { return IsDeployed(); }
+
+ void Cool( void );
+
+#ifdef CLIENT_DLL
+ virtual void ClientThink( void );
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void CleanupToolRecordingState( KeyValues *msg );
+
+ void EmitSmokeParticle( void );
+#else
+ void CoolThink( void );
+#endif
+
+ virtual float GetRecoil( void );
+
+private:
+ CWeaponMG42( const CWeaponMG42 & );
+
+ CNetworkVar( int, m_iWeaponHeat );
+ CNetworkVar( float, m_flNextCoolTime );
+
+ CNetworkVar( bool, m_bOverheated );
+
+#ifdef CLIENT_DLL
+
+ CSmartPtr<CSimpleEmitter> m_pEmitter;
+
+ float m_flParticleAccumulator;
+ PMaterialHandle m_hParticleMaterial;
+
+#endif
+
+};
+
+#endif //WEAPON_MG42_H \ No newline at end of file
diff --git a/game/shared/dod/weapon_mp40.cpp b/game/shared/dod/weapon_mp40.cpp
new file mode 100644
index 0000000..ba1f23f
--- /dev/null
+++ b/game/shared/dod/weapon_mp40.cpp
@@ -0,0 +1,94 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodfullauto_punch.h"
+
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponMP40 C_WeaponMP40
+
+#endif
+
+
+class CWeaponMP40 : public CDODFullAutoPunchWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponMP40, CDODFullAutoPunchWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponMP40() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_MP40; }
+ virtual DODWeaponID GetAltWeaponID( void ) const { return WEAPON_MP40_PUNCH; }
+
+ virtual Activity GetIdleActivity( void );
+
+ virtual float GetRecoil( void ) { return 2.2f; }
+
+private:
+ CWeaponMP40( const CWeaponMP40 & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponMP40, DT_WeaponMP40 )
+
+BEGIN_NETWORK_TABLE( CWeaponMP40, DT_WeaponMP40 )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponMP40 )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_mp40, CWeaponMP40 );
+PRECACHE_WEAPON_REGISTER( weapon_mp40 );
+
+acttable_t CWeaponMP40::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_MP40, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_MP40, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_MP40, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_MP40, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_MP40, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_MP40, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_MP40, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_MP40, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_MP40, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_MP40, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_MP40, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_MP40, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_MP40, false },
+
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_MP40, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_MP40, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_MP40, false },
+ { ACT_RANGE_ATTACK2, ACT_DOD_SECONDARYATTACK_MP40, false },
+ { ACT_DOD_SECONDARYATTACK_CROUCH, ACT_DOD_SECONDARYATTACK_CROUCH_MP40,false },
+ { ACT_DOD_SECONDARYATTACK_PRONE, ACT_DOD_SECONDARYATTACK_PRONE_MP40, false },
+
+ { ACT_RELOAD, ACT_DOD_RELOAD_MP40, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_MP40, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_MP40, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_MP44, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_MP44, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponMP40 );
+
+Activity CWeaponMP40::GetIdleActivity( void )
+{
+ Activity actIdle;
+
+ if( m_iClip1 < GetMaxClip1() )
+ actIdle = ACT_VM_IDLE_EMPTY;
+ else
+ actIdle = ACT_VM_IDLE;
+
+ return actIdle;
+}
diff --git a/game/shared/dod/weapon_mp44.cpp b/game/shared/dod/weapon_mp44.cpp
new file mode 100644
index 0000000..1c2ccad
--- /dev/null
+++ b/game/shared/dod/weapon_mp44.cpp
@@ -0,0 +1,87 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodfireselect.h"
+
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponMP44 C_WeaponMP44
+
+#endif
+
+
+class CWeaponMP44 : public CDODFireSelectWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponMP44, CDODFireSelectWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponMP44() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_MP44; }
+
+ // weapon id for stats purposes
+ virtual DODWeaponID GetStatsWeaponID( void )
+ {
+ if ( IsSemiAuto() )
+ return WEAPON_MP44_SEMIAUTO;
+ else
+ return WEAPON_MP44;
+ }
+
+ virtual float GetRecoil( void ) { return 5.0f; }
+
+private:
+ CWeaponMP44( const CWeaponMP44 & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponMP44, DT_WeaponMP44 )
+
+BEGIN_NETWORK_TABLE( CWeaponMP44, DT_WeaponMP44 )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponMP44 )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_mp44, CWeaponMP44 );
+PRECACHE_WEAPON_REGISTER( weapon_mp44 );
+
+acttable_t CWeaponMP44::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_MP44, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_MP44, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_MP44, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_MP44, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_MP44, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_MP44, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_MP44, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_MP44, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_MP44, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_MP44, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_MP44, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_MP44, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_MP44, false },
+
+ // Attack ( prone? )
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_MP44, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_MP44, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_MP44, false },
+
+ // Reload ( prone? )
+ { ACT_RELOAD, ACT_DOD_RELOAD_MP44, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_MP44, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_MP44, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_MP44, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_MP44, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponMP44 ); \ No newline at end of file
diff --git a/game/shared/dod/weapon_p38.cpp b/game/shared/dod/weapon_p38.cpp
new file mode 100644
index 0000000..348d720
--- /dev/null
+++ b/game/shared/dod/weapon_p38.cpp
@@ -0,0 +1,115 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodsemiauto.h"
+
+#if defined( CLIENT_DLL )
+
+#define CWeaponP38 C_WeaponP38
+
+#endif
+
+
+class CWeaponP38 : public CDODSemiAutoWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponP38, CDODSemiAutoWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponP38() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_P38; }
+
+ virtual Activity GetIdleActivity( void );
+ virtual Activity GetPrimaryAttackActivity( void );
+ virtual Activity GetDrawActivity( void );
+
+ virtual float GetRecoil( void ) { return 1.4f; }
+
+private:
+ CWeaponP38( const CWeaponP38 & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponP38, DT_WeaponP38 )
+
+BEGIN_NETWORK_TABLE( CWeaponP38, DT_WeaponP38 )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponP38 )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_p38, CWeaponP38 );
+PRECACHE_WEAPON_REGISTER( weapon_p38 );
+
+acttable_t CWeaponP38::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_PISTOL, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_PISTOL, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_PISTOL, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_PISTOL, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_PISTOL, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_PISTOL, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_PISTOL, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_PISTOL, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_PISTOL, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_PISTOL, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_PISTOL, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_PISTOL, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_PISTOL, false },
+
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_PISTOL, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_PISTOL, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_PISTOL, false },
+
+ { ACT_RELOAD, ACT_DOD_RELOAD_PISTOL, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_PISTOL, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_PISTOL, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_PISTOL, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_PISTOL, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponP38 );
+
+Activity CWeaponP38::GetIdleActivity( void )
+{
+ Activity actIdle;
+
+ if( m_iClip1 <= 0 )
+ actIdle = ACT_VM_IDLE_EMPTY;
+ else
+ actIdle = ACT_VM_IDLE;
+
+ return actIdle;
+}
+
+Activity CWeaponP38::GetPrimaryAttackActivity( void )
+{
+ Activity actPrim;
+
+ if( m_iClip1 <= 0 )
+ actPrim = ACT_VM_PRIMARYATTACK_EMPTY;
+ else
+ actPrim = ACT_VM_PRIMARYATTACK;
+
+ return actPrim;
+}
+
+Activity CWeaponP38::GetDrawActivity( void )
+{
+ Activity actDraw;
+
+ if( m_iClip1 <= 0 )
+ actDraw = ACT_VM_DRAW_EMPTY;
+ else
+ actDraw = ACT_VM_DRAW;
+
+ return actDraw;
+} \ No newline at end of file
diff --git a/game/shared/dod/weapon_pschreck.cpp b/game/shared/dod/weapon_pschreck.cpp
new file mode 100644
index 0000000..89e52fa
--- /dev/null
+++ b/game/shared/dod/weapon_pschreck.cpp
@@ -0,0 +1,102 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbaserpg.h"
+
+#ifndef CLIENT_DLL
+ #include "rocket_pschreck.h"
+#endif
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponPschreck C_WeaponPschreck
+
+#endif
+
+
+class CWeaponPschreck : public CDODBaseRocketWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponPschreck, CDODBaseRocketWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponPschreck() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_PSCHRECK; }
+
+ virtual void FireRocket( void );
+
+private:
+ CWeaponPschreck( const CWeaponPschreck & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponPschreck, DT_WeaponPschreck )
+
+BEGIN_NETWORK_TABLE( CWeaponPschreck, DT_WeaponPschreck )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponPschreck )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_pschreck, CWeaponPschreck );
+PRECACHE_WEAPON_REGISTER( weapon_pschreck );
+
+acttable_t CWeaponPschreck::m_acttable[] =
+{
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_PSCHRECK, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_PSCHRECK, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_PSCHRECK, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_PSCHRECK, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_PSCHRECK, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_PSCHRECK, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_PSCHRECK, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_PSCHRECK, false },
+
+ // Zoomed Aim
+ { ACT_DOD_IDLE_ZOOMED, ACT_DOD_STAND_ZOOM_PSCHRECK, false },
+ { ACT_DOD_CROUCH_ZOOMED, ACT_DOD_CROUCH_ZOOM_PSCHRECK, false },
+ { ACT_DOD_CROUCHWALK_ZOOMED, ACT_DOD_CROUCHWALK_ZOOM_PSCHRECK, false },
+ { ACT_DOD_WALK_ZOOMED, ACT_DOD_WALK_ZOOM_PSCHRECK, false },
+ { ACT_DOD_PRONE_ZOOMED, ACT_DOD_PRONE_ZOOM_PSCHRECK, false },
+ { ACT_DOD_PRONE_FORWARD_ZOOMED, ACT_DOD_PRONE_ZOOM_FORWARD_PSCHRECK, false },
+
+ // Attack ( must be zoomed )
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_PSCHRECK, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_PSCHRECK, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_PSCHRECK, false },
+
+ // Reload ( zoomed or not, prone or not )
+ { ACT_RELOAD, ACT_DOD_RELOAD_PSCHRECK, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_PSCHRECK, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_PSCHRECK, false },
+ { ACT_DOD_RELOAD_DEPLOYED, ACT_DOD_ZOOMLOAD_PSCHRECK, false },
+ { ACT_DOD_RELOAD_PRONE_DEPLOYED, ACT_DOD_ZOOMLOAD_PRONE_PSCHRECK, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_PSCHRECK, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_PSCHRECK, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponPschreck );
+
+void CWeaponPschreck::FireRocket( void )
+{
+#ifndef CLIENT_DLL
+
+ CBasePlayer *pPlayer = GetPlayerOwner();
+
+#ifdef DBGFLAG_ASSERT
+ CPschreckRocket *pRocket =
+#endif //DEBUG
+ CPschreckRocket::Create( pPlayer->Weapon_ShootPosition(), pPlayer->GetAbsAngles(), pPlayer );
+
+ Assert( pRocket );
+
+#endif
+}
diff --git a/game/shared/dod/weapon_riflegrenade.cpp b/game/shared/dod/weapon_riflegrenade.cpp
new file mode 100644
index 0000000..b6c7abc
--- /dev/null
+++ b/game/shared/dod/weapon_riflegrenade.cpp
@@ -0,0 +1,233 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "fx_dod_shared.h"
+#include "weapon_riflegrenade.h"
+
+#ifdef CLIENT_DLL
+ #include "prediction.h"
+#endif
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponBaseRifleGrenade, DT_WeaponBaseRifleGrenade )
+
+BEGIN_NETWORK_TABLE( CWeaponBaseRifleGrenade, DT_WeaponBaseRifleGrenade )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponBaseRifleGrenade )
+END_PREDICTION_DATA()
+
+
+CWeaponBaseRifleGrenade::CWeaponBaseRifleGrenade()
+{
+}
+
+void CWeaponBaseRifleGrenade::Spawn()
+{
+ BaseClass::Spawn();
+}
+
+void CWeaponBaseRifleGrenade::PrimaryAttack( void )
+{
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+ Assert( pPlayer );
+
+ // Out of ammo?
+ if ( m_iClip1 <= 0 )
+ {
+ if (m_bFireOnEmpty)
+ {
+ PlayEmptySound();
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
+ }
+ return;
+ }
+
+ if( pPlayer->GetWaterLevel() > 2 )
+ {
+ PlayEmptySound();
+ m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
+ return;
+ }
+
+ // decrement before calling PlayPrimaryAttackAnim, so we can play the empty anim if necessary
+ m_iClip1--;
+
+ SendWeaponAnim( ACT_VM_PRIMARYATTACK );
+
+ // player "shoot" animation
+ pPlayer->SetAnimation( PLAYER_ATTACK1 );
+
+#ifdef CLIENT_DLL
+ if( pPlayer && !pPlayer->IsDormant() )
+ pPlayer->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN );
+#else
+ if( pPlayer )
+ pPlayer->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN );
+#endif
+
+#ifndef CLIENT_DLL
+ ShootGrenade();
+#endif
+
+ WeaponSound( SINGLE );
+
+ DoFireEffects();
+
+#ifdef CLIENT_DLL
+ CDODPlayer *p = ToDODPlayer( GetPlayerOwner() );
+
+ if ( prediction->IsFirstTimePredicted() )
+ p->DoRecoil( GetWeaponID(), GetRecoil() );
+#endif
+
+ m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + GetFireDelay();
+ m_flTimeWeaponIdle = gpGlobals->curtime + m_pWeaponInfo->m_flTimeToIdleAfterFire;
+
+#ifndef CLIENT_DLL
+ IGameEvent * event = gameeventmanager->CreateEvent( "dod_stats_weapon_attack" );
+ if ( event )
+ {
+ event->SetInt( "attacker", pPlayer->GetUserID() );
+ event->SetInt( "weapon", GetStatsWeaponID() );
+
+ gameeventmanager->FireEvent( event );
+ }
+#endif //CLIENT_DLL
+}
+
+Activity CWeaponBaseRifleGrenade::GetDrawActivity( void )
+{
+ return ( (m_iClip1 <= 0 ) ? ACT_VM_DRAW_EMPTY : ACT_VM_DRAW );
+}
+
+Activity CWeaponBaseRifleGrenade::GetIdleActivity( void )
+{
+ return ( (m_iClip1 <= 0 ) ? ACT_VM_IDLE_EMPTY : ACT_VM_IDLE );
+}
+
+bool CWeaponBaseRifleGrenade::Holster( CBaseCombatWeapon *pSwitchingTo )
+{
+#ifndef CLIENT_DLL
+ // If they attempt to switch weapons before the throw animation is done,
+ // allow it, but kill the weapon if we have to.
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+
+ if( pPlayer && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 && m_iClip1 <= 0 )
+ {
+ pPlayer->Weapon_Drop( this, NULL, NULL );
+ UTIL_Remove(this);
+ return true;
+ }
+#endif
+
+ return BaseClass::Holster( pSwitchingTo );
+}
+
+// weapon idle to destroy weapon if empty
+void CWeaponBaseRifleGrenade::WeaponIdle( void )
+{
+#ifndef CLIENT_DLL
+ CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
+ if (pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 && m_iClip1 <= 0)
+ {
+ pPlayer->Weapon_Drop( this, NULL, NULL );
+ UTIL_Remove(this);
+ return;
+ }
+#endif
+
+ BaseClass::WeaponIdle();
+}
+
+#define DOD_RIFLEGRENADE_SPEED 2000
+extern ConVar dod_grenadegravity;
+
+#ifndef CLIENT_DLL
+
+ void CWeaponBaseRifleGrenade::ShootGrenade( void )
+ {
+ CDODPlayer *pPlayer = ToDODPlayer( GetOwner() );
+ if ( !pPlayer )
+ {
+ Assert( false );
+ return;
+ }
+
+ QAngle angThrow = pPlayer->LocalEyeAngles();
+
+ Vector vForward, vRight, vUp;
+ AngleVectors( angThrow, &vForward, &vRight, &vUp );
+
+ Vector eyes = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset();
+ Vector vecSrc = eyes;
+ Vector vecThrow = vForward * DOD_RIFLEGRENADE_SPEED;
+
+ // raise origin enough so that you can't shoot it straight down through the world
+ if ( pPlayer->m_Shared.IsProne() )
+ {
+ vecSrc.z += 16;
+ }
+
+ SetCollisionGroup( COLLISION_GROUP_WEAPON );
+
+ QAngle angles;
+ VectorAngles( -vecThrow, angles );
+
+ // estimate angular velocity based on initial conditions
+ // uses a constant ang velocity instead of the derivative of the flight path, oh well.
+ AngularImpulse angImpulse;
+ angImpulse.Init();
+
+ if ( vecThrow.z > 0 )
+ angImpulse.y = -angles.x / ( sqrt( (-2 * vecThrow.z) / dod_grenadegravity.GetFloat() ));
+ else
+ angImpulse.y = -10;
+
+ EmitGrenade( vecSrc, angles, vecThrow, angImpulse, pPlayer, RIFLEGRENADE_FUSE_LENGTH );
+ }
+
+ void CWeaponBaseRifleGrenade::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime )
+ {
+ Assert( !"Deriving classes should define this" );
+ }
+
+#endif
+
+bool CWeaponBaseRifleGrenade::CanDeploy( void )
+{
+ // does the player own the weapon that fires this grenade?
+ CBasePlayer *pPlayer = GetPlayerOwner();
+
+ if ( !pPlayer )
+ return false;
+
+ CBaseCombatWeapon *pOwnedWeapon = pPlayer->Weapon_OwnsThisType( GetCompanionWeaponName() );
+
+ if ( pOwnedWeapon == NULL )
+ return false;
+
+ return BaseClass::CanDeploy();
+}
+
+const char *CWeaponBaseRifleGrenade::GetCompanionWeaponName( void )
+{
+ Assert( !"Should not call this version. Inheriting classes must implement." );
+ return "";
+}
+
+float CWeaponBaseRifleGrenade::GetRecoil( void )
+{
+ CDODPlayer *p = ToDODPlayer( GetPlayerOwner() );
+
+ if( p && p->m_Shared.IsInMGDeploy() )
+ {
+ return 0.0f;
+ }
+
+ return 10;
+} \ No newline at end of file
diff --git a/game/shared/dod/weapon_riflegrenade.h b/game/shared/dod/weapon_riflegrenade.h
new file mode 100644
index 0000000..f989f53
--- /dev/null
+++ b/game/shared/dod/weapon_riflegrenade.h
@@ -0,0 +1,48 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "shake.h"
+#include "weapon_dodbasegun.h"
+
+#if defined( CLIENT_DLL )
+#define CWeaponBaseRifleGrenade C_WeaponBaseRifleGrenade
+#endif
+
+class CWeaponBaseRifleGrenade : public CWeaponDODBaseGun
+{
+public:
+ DECLARE_CLASS( CWeaponBaseRifleGrenade, CWeaponDODBaseGun );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CWeaponBaseRifleGrenade();
+
+ virtual void Spawn();
+ virtual void PrimaryAttack( void );
+ virtual bool Holster( CBaseCombatWeapon *pSwitchingTo );
+ virtual void WeaponIdle( void );
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_NONE; }
+
+
+ virtual Activity GetDrawActivity( void );
+ virtual Activity GetIdleActivity( void );
+
+ virtual bool CanDeploy( void );
+
+ virtual const char *GetCompanionWeaponName( void );
+
+ virtual float GetRecoil( void );
+
+#ifndef CLIENT_DLL
+ void ShootGrenade( void );
+ virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime );
+#endif
+
+private:
+ CWeaponBaseRifleGrenade( const CWeaponBaseRifleGrenade & );
+}; \ No newline at end of file
diff --git a/game/shared/dod/weapon_riflegrenade_ger.cpp b/game/shared/dod/weapon_riflegrenade_ger.cpp
new file mode 100644
index 0000000..99afd1b
--- /dev/null
+++ b/game/shared/dod/weapon_riflegrenade_ger.cpp
@@ -0,0 +1,91 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_riflegrenade.h"
+
+#if defined( CLIENT_DLL )
+
+#include "c_dod_player.h"
+#define CWeaponRifleGrenadeGER C_WeaponRifleGrenadeGER
+
+#else
+
+#include "dod_riflegrenade_ger.h"
+#include "dod_player.h"
+
+#endif
+
+class CWeaponRifleGrenadeGER : public CWeaponBaseRifleGrenade
+{
+public:
+ DECLARE_CLASS( CWeaponRifleGrenadeGER, CWeaponBaseRifleGrenade );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponRifleGrenadeGER() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_RIFLEGREN_GER; }
+
+#ifndef CLIENT_DLL
+ virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime = GRENADE_FUSE_LENGTH )
+ {
+ CDODRifleGrenadeGER::Create( vecSrc, vecAngles, vecVel, angImpulse, pPlayer, flLifeTime, GetWeaponID() );
+ }
+#endif
+
+ virtual const char *GetCompanionWeaponName( void )
+ {
+ return "weapon_k98";
+ }
+
+private:
+ CWeaponRifleGrenadeGER( const CWeaponRifleGrenadeGER & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponRifleGrenadeGER, DT_WeaponRifleGrenadeGER )
+
+BEGIN_NETWORK_TABLE( CWeaponRifleGrenadeGER, DT_WeaponRifleGrenadeGER )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponRifleGrenadeGER )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_riflegren_ger, CWeaponRifleGrenadeGER );
+PRECACHE_WEAPON_REGISTER( weapon_riflegren_ger );
+
+acttable_t CWeaponRifleGrenadeGER::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_RIFLE, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_RIFLE, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_RIFLE, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_RIFLE, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_RIFLE, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_RIFLE, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_RIFLE, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_RIFLE, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_RIFLE, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_RIFLE, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_RIFLE, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_RIFLE, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_RIFLE, false },
+
+ // Attack ( prone? deployed? )
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_RIFLE, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_RIFLE, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_RIFLE, false },
+
+ { ACT_RELOAD, ACT_DOD_RELOAD_RIFLEGRENADE, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_RIFLEGRENADE, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_RIFLEGRENADE, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_K98, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_K98, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponRifleGrenadeGER );
diff --git a/game/shared/dod/weapon_riflegrenade_ger_live.cpp b/game/shared/dod/weapon_riflegrenade_ger_live.cpp
new file mode 100644
index 0000000..fce54d1
--- /dev/null
+++ b/game/shared/dod/weapon_riflegrenade_ger_live.cpp
@@ -0,0 +1,56 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasegrenade.h"
+
+#ifdef CLIENT_DLL
+#define CWeaponRifleGrenadeGER_Live C_WeaponRifleGrenadeGER_Live
+#else
+#include "dod_riflegrenade_ger.h" //the thing that we throw
+#endif
+
+
+class CWeaponRifleGrenadeGER_Live : public CWeaponDODBaseGrenade
+{
+public:
+ DECLARE_CLASS( CWeaponRifleGrenadeGER_Live, CWeaponDODBaseGrenade );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CWeaponRifleGrenadeGER_Live() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_RIFLEGREN_GER_LIVE; }
+
+#ifndef CLIENT_DLL
+
+ virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime = GRENADE_FUSE_LENGTH )
+ {
+ // align the grenade vertically and spin end over end
+ QAngle vecNewAngles = QAngle(45,pPlayer->EyeAngles().y,0);
+ AngularImpulse angNewImpulse = AngularImpulse( 0, 600, 0 );
+
+ CDODRifleGrenadeGER::Create( vecSrc, vecNewAngles, vecVel, angNewImpulse, pPlayer, flLifeTime, GetWeaponID() );
+ }
+
+#endif
+
+ virtual bool IsArmed( void ) { return true; }
+
+private:
+ CWeaponRifleGrenadeGER_Live( const CWeaponRifleGrenadeGER_Live & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponRifleGrenadeGER_Live, DT_WeaponRifleGrenadeGER_Live )
+
+BEGIN_NETWORK_TABLE(CWeaponRifleGrenadeGER_Live, DT_WeaponRifleGrenadeGER_Live)
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponRifleGrenadeGER_Live )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_riflegren_ger_live, CWeaponRifleGrenadeGER_Live );
+PRECACHE_WEAPON_REGISTER( weapon_riflegren_ger_live ); \ No newline at end of file
diff --git a/game/shared/dod/weapon_riflegrenade_us.cpp b/game/shared/dod/weapon_riflegrenade_us.cpp
new file mode 100644
index 0000000..db152d0
--- /dev/null
+++ b/game/shared/dod/weapon_riflegrenade_us.cpp
@@ -0,0 +1,91 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_riflegrenade.h"
+
+#if defined( CLIENT_DLL )
+
+ #include "c_dod_player.h"
+ #define CWeaponRifleGrenadeUS C_WeaponRifleGrenadeUS
+
+#else
+
+ #include "dod_riflegrenade_us.h"
+ #include "dod_player.h"
+
+#endif
+
+class CWeaponRifleGrenadeUS : public CWeaponBaseRifleGrenade
+{
+public:
+ DECLARE_CLASS( CWeaponRifleGrenadeUS, CWeaponBaseRifleGrenade );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponRifleGrenadeUS() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_RIFLEGREN_US; }
+
+#ifndef CLIENT_DLL
+ virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime = GRENADE_FUSE_LENGTH )
+ {
+ CDODRifleGrenadeUS::Create( vecSrc, vecAngles, vecVel, angImpulse, pPlayer, flLifeTime, GetWeaponID() );
+ }
+#endif
+
+ virtual const char *GetCompanionWeaponName( void )
+ {
+ return "weapon_garand";
+ }
+
+private:
+ CWeaponRifleGrenadeUS( const CWeaponRifleGrenadeUS & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponRifleGrenadeUS, DT_WeaponRifleGrenadeUS )
+
+BEGIN_NETWORK_TABLE( CWeaponRifleGrenadeUS, DT_WeaponRifleGrenadeUS )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponRifleGrenadeUS )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_riflegren_us, CWeaponRifleGrenadeUS );
+PRECACHE_WEAPON_REGISTER( weapon_riflegren_us );
+
+acttable_t CWeaponRifleGrenadeUS::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_RIFLE, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_RIFLE, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_RIFLE, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_RIFLE, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_RIFLE, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_RIFLE, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_RIFLE, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_RIFLE, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_RIFLE, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_RIFLE, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_RIFLE, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_RIFLE, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_RIFLE, false },
+
+ // Attack ( prone? deployed? )
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_RIFLE, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_RIFLE, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_RIFLE, false },
+
+ { ACT_RELOAD, ACT_DOD_RELOAD_RIFLEGRENADE, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_RIFLEGRENADE, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_RIFLEGRENADE, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_K98, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_K98, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponRifleGrenadeUS );
diff --git a/game/shared/dod/weapon_riflegrenade_us_live.cpp b/game/shared/dod/weapon_riflegrenade_us_live.cpp
new file mode 100644
index 0000000..039c6fa
--- /dev/null
+++ b/game/shared/dod/weapon_riflegrenade_us_live.cpp
@@ -0,0 +1,56 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasegrenade.h"
+
+#ifdef CLIENT_DLL
+#define CWeaponRifleGrenadeUS_Live C_WeaponRifleGrenadeUS_Live
+#else
+#include "dod_riflegrenade_us.h" //the thing that we throw
+#endif
+
+
+class CWeaponRifleGrenadeUS_Live : public CWeaponDODBaseGrenade
+{
+public:
+ DECLARE_CLASS( CWeaponRifleGrenadeUS_Live, CWeaponDODBaseGrenade );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CWeaponRifleGrenadeUS_Live() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_RIFLEGREN_US_LIVE; }
+
+#ifndef CLIENT_DLL
+
+ virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime = GRENADE_FUSE_LENGTH )
+ {
+ // align the grenade vertically and spin end over end
+ QAngle vecNewAngles = QAngle(45,pPlayer->EyeAngles().y,0);
+ AngularImpulse angNewImpulse = AngularImpulse( 0, 600, 0 );
+
+ CDODRifleGrenadeUS::Create( vecSrc, vecNewAngles, vecVel, angNewImpulse, pPlayer, flLifeTime, GetWeaponID() );
+ }
+
+#endif
+
+ virtual bool IsArmed( void ) { return true; }
+
+private:
+ CWeaponRifleGrenadeUS_Live( const CWeaponRifleGrenadeUS_Live & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponRifleGrenadeUS_Live, DT_WeaponRifleGrenadeUS_Live )
+
+BEGIN_NETWORK_TABLE(CWeaponRifleGrenadeUS_Live, DT_WeaponRifleGrenadeUS_Live)
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponRifleGrenadeUS_Live )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_riflegren_us_live, CWeaponRifleGrenadeUS_Live );
+PRECACHE_WEAPON_REGISTER( weapon_riflegren_us_live ); \ No newline at end of file
diff --git a/game/shared/dod/weapon_smokegrenade_ger.cpp b/game/shared/dod/weapon_smokegrenade_ger.cpp
new file mode 100644
index 0000000..6d9e310
--- /dev/null
+++ b/game/shared/dod/weapon_smokegrenade_ger.cpp
@@ -0,0 +1,55 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasegrenade.h"
+
+#ifdef CLIENT_DLL
+#define CWeaponSmokeGrenadeGER C_WeaponSmokeGrenadeGER
+#else
+#include "dod_smokegrenade_ger.h" //the thing that we throw
+#endif
+
+class CWeaponSmokeGrenadeGER : public CWeaponDODBaseGrenade
+{
+public:
+ DECLARE_CLASS( CWeaponSmokeGrenadeGER, CWeaponDODBaseGrenade );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CWeaponSmokeGrenadeGER() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_SMOKE_GER; }
+
+#ifndef CLIENT_DLL
+
+ virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime = GRENADE_FUSE_LENGTH )
+ {
+ // align the stickgrenade vertically and spin end over end
+ QAngle vecNewAngles = QAngle(45,pPlayer->EyeAngles().y,0);
+ AngularImpulse angNewImpulse = AngularImpulse( 0, 600, 0 );
+
+ CDODSmokeGrenadeGER::Create( vecSrc, vecNewAngles, vecVel, angNewImpulse, pPlayer );
+ }
+
+#endif
+
+ virtual float GetDetonateTimerLength( void ) { return 10; }
+
+private:
+ CWeaponSmokeGrenadeGER( const CWeaponSmokeGrenadeGER & ) {}
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponSmokeGrenadeGER, DT_WeaponSmokeGrenadeGER )
+
+BEGIN_NETWORK_TABLE(CWeaponSmokeGrenadeGER, DT_WeaponSmokeGrenadeGER)
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponSmokeGrenadeGER )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_smoke_ger, CWeaponSmokeGrenadeGER );
+PRECACHE_WEAPON_REGISTER( weapon_smoke_ger ); \ No newline at end of file
diff --git a/game/shared/dod/weapon_smokegrenade_us.cpp b/game/shared/dod/weapon_smokegrenade_us.cpp
new file mode 100644
index 0000000..69c71ce
--- /dev/null
+++ b/game/shared/dod/weapon_smokegrenade_us.cpp
@@ -0,0 +1,51 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasegrenade.h"
+
+#ifdef CLIENT_DLL
+ #define CWeaponSmokeGrenadeUS C_WeaponSmokeGrenadeUS
+#else
+ #include "dod_smokegrenade_us.h" //the thing that we throw
+#endif
+
+class CWeaponSmokeGrenadeUS : public CWeaponDODBaseGrenade
+{
+public:
+ DECLARE_CLASS( CWeaponSmokeGrenadeUS, CWeaponDODBaseGrenade );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CWeaponSmokeGrenadeUS() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_SMOKE_US; }
+
+#ifndef CLIENT_DLL
+
+ virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime = GRENADE_FUSE_LENGTH )
+ {
+ CDODSmokeGrenadeUS::Create( vecSrc, vecAngles, vecVel, angImpulse, pPlayer );
+ }
+
+#endif
+
+ virtual float GetDetonateTimerLength( void ) { return 10; }
+
+private:
+ CWeaponSmokeGrenadeUS( const CWeaponSmokeGrenadeUS & ) {}
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponSmokeGrenadeUS, DT_WeaponSmokeGrenadeUS )
+
+BEGIN_NETWORK_TABLE(CWeaponSmokeGrenadeUS, DT_WeaponSmokeGrenadeUS)
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponSmokeGrenadeUS )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_smoke_us, CWeaponSmokeGrenadeUS );
+PRECACHE_WEAPON_REGISTER( weapon_smoke_us ); \ No newline at end of file
diff --git a/game/shared/dod/weapon_spade.cpp b/game/shared/dod/weapon_spade.cpp
new file mode 100644
index 0000000..4df7d21
--- /dev/null
+++ b/game/shared/dod/weapon_spade.cpp
@@ -0,0 +1,71 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasemelee.h"
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponSpade C_WeaponSpade
+
+#endif
+
+
+class CWeaponSpade : public CWeaponDODBaseMelee
+{
+public:
+ DECLARE_CLASS( CWeaponSpade, CWeaponDODBaseMelee );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponSpade() {}
+
+ virtual Activity GetMeleeActivity( void ) { return ACT_VM_PRIMARYATTACK; }
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_SPADE; }
+
+private:
+ CWeaponSpade( const CWeaponSpade & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponSpade, DT_WeaponSpade )
+
+BEGIN_NETWORK_TABLE( CWeaponSpade, DT_WeaponSpade )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponSpade )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_spade, CWeaponSpade );
+PRECACHE_WEAPON_REGISTER( weapon_spade );
+
+acttable_t CWeaponSpade::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_SPADE, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_SPADE, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_SPADE, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_SPADE, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_SPADE, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_SPADE, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_AIM_SPADE, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_AIM_SPADE, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_AIM_SPADE, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_AIM_SPADE, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_AIM_SPADE, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_AIM_SPADE, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_AIM_SPADE, false },
+
+ { ACT_RANGE_ATTACK2, ACT_DOD_PRIMARYATTACK_SPADE, false },
+ { ACT_DOD_SECONDARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_CROUCH_SPADE, false },
+ { ACT_DOD_SECONDARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_SPADE, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_STICKGRENADE, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_STICKGRENADE, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponSpade ); \ No newline at end of file
diff --git a/game/shared/dod/weapon_spring.cpp b/game/shared/dod/weapon_spring.cpp
new file mode 100644
index 0000000..9f9ed67
--- /dev/null
+++ b/game/shared/dod/weapon_spring.cpp
@@ -0,0 +1,156 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodsniper.h"
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponSpring C_WeaponSpring
+
+#endif
+
+
+class CWeaponSpring : public CDODSniperWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponSpring, CDODSniperWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponSpring() {}
+
+ virtual void Spawn( void );
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_SPRING; }
+
+ // weapon id for stats purposes
+ virtual DODWeaponID GetStatsWeaponID( void )
+ {
+ if ( IsFullyZoomed() )
+ return WEAPON_SPRING_ZOOMED;
+ else
+ return WEAPON_SPRING;
+ }
+
+ virtual bool ShouldAutoEjectBrass( void ) { return false; }
+ virtual bool ShouldDrawCrosshair( void ) { return false; }
+
+ virtual bool ShouldDrawViewModel( void )
+ {
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+
+ Assert( pPlayer );
+
+ if ( !pPlayer )
+ return false;
+
+ if ( pPlayer->GetFOV() < 90 )
+ return false;
+
+ // handle case when we are spectating someone and don't know their fov
+ if ( IsFullyZoomed() )
+ return false;
+
+ return BaseClass::ShouldDrawViewModel();
+ }
+
+ virtual bool ShouldDrawMuzzleFlash( void )
+ {
+ return ShouldDrawViewModel();
+ }
+
+ virtual Activity GetPrimaryAttackActivity( void );
+
+ virtual float GetFireDelay( void );
+
+ virtual float GetRecoil( void ) { return 5.6f; }
+
+private:
+ CWeaponSpring( const CWeaponSpring & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponSpring, DT_WeaponSpring )
+
+BEGIN_NETWORK_TABLE( CWeaponSpring, DT_WeaponSpring )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponSpring )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_spring, CWeaponSpring );
+PRECACHE_WEAPON_REGISTER( weapon_spring );
+
+void CWeaponSpring::Spawn( void )
+{
+ m_iAltFireHint = HINT_USE_ZOOM;
+
+ BaseClass::Spawn();
+}
+
+acttable_t CWeaponSpring::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_BOLT, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_BOLT, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_BOLT, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_BOLT, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_BOLT, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_BOLT, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_BOLT, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_BOLT, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_BOLT, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_BOLT, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_BOLT, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_BOLT, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_BOLT, false },
+
+ // Zoomed Aim
+ { ACT_DOD_IDLE_ZOOMED, ACT_DOD_STAND_ZOOM_BOLT, false },
+ { ACT_DOD_CROUCH_ZOOMED, ACT_DOD_CROUCH_ZOOM_BOLT, false },
+ { ACT_DOD_CROUCHWALK_ZOOMED, ACT_DOD_CROUCHWALK_ZOOM_BOLT, false },
+ { ACT_DOD_WALK_ZOOMED, ACT_DOD_WALK_ZOOM_BOLT, false },
+ { ACT_DOD_PRONE_ZOOMED, ACT_DOD_PRONE_ZOOM_BOLT, false },
+ { ACT_DOD_PRONE_FORWARD_ZOOMED, ACT_DOD_PRONE_ZOOM_FORWARD_BOLT, false },
+
+ // Attack ( prone? )
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_BOLT, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_BOLT, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_BOLT, false },
+
+ // Reload ( prone ? )
+ { ACT_RELOAD, ACT_DOD_RELOAD_BOLT, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_BOLT, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_BOLT, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_K98, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_K98, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponSpring );
+
+Activity CWeaponSpring::GetPrimaryAttackActivity( void )
+{
+ Activity actPrim;
+
+ if( m_iClip1 <= 0 )
+ actPrim = ACT_VM_PRIMARYATTACK_EMPTY;
+ else
+ actPrim = ACT_VM_PRIMARYATTACK;
+
+ return actPrim;
+}
+
+float CWeaponSpring::GetFireDelay( void )
+{
+ if ( m_iClip1 <= 0 )
+ {
+ return SequenceDuration();
+ }
+
+ return BaseClass::GetFireDelay();
+}
diff --git a/game/shared/dod/weapon_stickgrenade.cpp b/game/shared/dod/weapon_stickgrenade.cpp
new file mode 100644
index 0000000..b8e94c5
--- /dev/null
+++ b/game/shared/dod/weapon_stickgrenade.cpp
@@ -0,0 +1,82 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodbasegrenade.h"
+
+#ifdef CLIENT_DLL
+ #define CWeaponStickGrenade C_WeaponStickGrenade
+#else
+ #include "dod_stickgrenade.h"
+#endif
+
+class CWeaponStickGrenade : public CWeaponDODBaseGrenade
+{
+public:
+ DECLARE_CLASS( CWeaponStickGrenade, CWeaponDODBaseGrenade );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponStickGrenade() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_FRAG_GER; }
+
+#ifndef CLIENT_DLL
+
+ virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime = GRENADE_FUSE_LENGTH )
+ {
+ // align the stickgrenade vertically and spin end over end
+ QAngle vecNewAngles = QAngle(45,pPlayer->EyeAngles().y,0);
+ AngularImpulse angNewImpulse = AngularImpulse( 0, 600, 0 );
+
+ CDODStickGrenade::Create( vecSrc, vecNewAngles, vecVel, angNewImpulse, pPlayer, flLifeTime, GetWeaponID() );
+ }
+
+#endif
+
+ CWeaponStickGrenade( const CWeaponStickGrenade & ) {}
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponStickGrenade, DT_WeaponStickGrenade )
+
+BEGIN_NETWORK_TABLE(CWeaponStickGrenade, DT_WeaponStickGrenade)
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponStickGrenade )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_frag_ger, CWeaponStickGrenade );
+PRECACHE_WEAPON_REGISTER( weapon_frag_ger );
+
+acttable_t CWeaponStickGrenade::m_acttable[] =
+{
+ // Move this out to the specific grenades???
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_GREN_STICK, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_GREN_STICK, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_GREN_STICK, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_GREN_STICK, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_GREN_STICK, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_GREN_STICK, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_AIM_GREN_STICK, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_AIM_GREN_STICK, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_AIM_GREN_STICK, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_AIM_GREN_STICK, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_AIM_GREN_STICK, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_AIM_GREN_STICK, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_AIM_GREN_STICK, false },
+
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_GREN_STICK, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_GREN_STICK, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_CROUCH_GREN_STICK, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_STICKGRENADE, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_STICKGRENADE, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponStickGrenade );
+
diff --git a/game/shared/dod/weapon_thompson.cpp b/game/shared/dod/weapon_thompson.cpp
new file mode 100644
index 0000000..d90e4f6
--- /dev/null
+++ b/game/shared/dod/weapon_thompson.cpp
@@ -0,0 +1,81 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_dodfullauto_punch.h"
+
+
+#if defined( CLIENT_DLL )
+
+ #define CWeaponThompson C_WeaponThompson
+
+#endif
+
+
+class CWeaponThompson : public CDODFullAutoPunchWeapon
+{
+public:
+ DECLARE_CLASS( CWeaponThompson, CDODFullAutoPunchWeapon );
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_ACTTABLE();
+
+ CWeaponThompson() {}
+
+ virtual DODWeaponID GetWeaponID( void ) const { return WEAPON_THOMPSON; }
+ virtual DODWeaponID GetAltWeaponID( void ) const { return WEAPON_THOMPSON_PUNCH; }
+
+ virtual float GetRecoil( void ) { return 2.15f; }
+
+private:
+ CWeaponThompson( const CWeaponThompson & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponThompson, DT_WeaponThompson )
+
+BEGIN_NETWORK_TABLE( CWeaponThompson, DT_WeaponThompson )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponThompson )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_thompson, CWeaponThompson );
+PRECACHE_WEAPON_REGISTER( weapon_thompson );
+
+acttable_t CWeaponThompson::m_acttable[] =
+{
+ { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_TOMMY, false },
+ { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_TOMMY, false },
+ { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_TOMMY, false },
+ { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_TOMMY, false },
+ { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_TOMMY, false },
+ { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_TOMMY, false },
+ { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_TOMMY, false },
+ { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_TOMMY, false },
+ { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_TOMMY, false },
+ { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_TOMMY, false },
+ { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_TOMMY, false },
+ { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_TOMMY, false },
+ { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_TOMMY, false },
+
+ { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_TOMMY, false },
+ { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_TOMMY, false },
+ { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_TOMMY, false },
+ { ACT_RANGE_ATTACK2, ACT_DOD_SECONDARYATTACK_TOMMY, false },
+ { ACT_DOD_SECONDARYATTACK_CROUCH, ACT_DOD_SECONDARYATTACK_CROUCH_TOMMY, false },
+ { ACT_DOD_SECONDARYATTACK_PRONE, ACT_DOD_SECONDARYATTACK_PRONE_TOMMY, false },
+
+ { ACT_RELOAD, ACT_DOD_RELOAD_TOMMY, false },
+ { ACT_DOD_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_TOMMY, false },
+ { ACT_DOD_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_TOMMY, false },
+
+ // Hand Signals
+ { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_TOMMY, false },
+ { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_TOMMY, false },
+};
+
+IMPLEMENT_ACTTABLE( CWeaponThompson );
+