mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-07 17:29:36 +00:00
1
This commit is contained in:
@@ -0,0 +1,727 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
#include <time.h>
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#include "achievementmgr.h"
|
||||
#include "baseachievement.h"
|
||||
#include "cs_achievement_constants.h"
|
||||
#include "c_cs_team.h"
|
||||
#include "c_cs_player.h"
|
||||
#include "c_cs_playerresource.h"
|
||||
#include "cs_gamerules.h"
|
||||
#include "achievements_cs.h"
|
||||
#include "cs_gamestats_shared.h"
|
||||
#include "cs_client_gamestats.h"
|
||||
|
||||
|
||||
// [dwenger] Necessary for stats display
|
||||
#include "cs_achievements_and_stats_interface.h"
|
||||
|
||||
// [dwenger] Necessary for sorting achievements by award time
|
||||
#include <vgui/ISystem.h>
|
||||
#include "../../src/public/vgui_controls/Controls.h"
|
||||
|
||||
|
||||
ConVar achievements_easymode( "achievement_easymode", "0", FCVAR_CLIENTDLL | FCVAR_DEVELOPMENTONLY,
|
||||
"Enables all stat-based achievements to be earned at 10% of goals" );
|
||||
|
||||
// global achievement mgr for CS
|
||||
CAchievementMgr g_AchievementMgrCS;
|
||||
|
||||
// [dwenger] Necessary for achievement / stats panel
|
||||
CSAchievementsAndStatsInterface g_AchievementsAndStatsInterfaceCS;
|
||||
|
||||
|
||||
CCSBaseAchievement::CCSBaseAchievement()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Determines the timestamp when the achievement is awarded
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCSBaseAchievement::OnAchieved()
|
||||
{
|
||||
// __time32_t unlockTime;
|
||||
// _time32(&unlockTime);
|
||||
// SetUnlockTime(unlockTime);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the time values when the achievement was awarded.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CCSBaseAchievement::GetAwardTime( int& year, int& month, int& day, int& hour, int& minute, int& second )
|
||||
{
|
||||
time_t t = GetUnlockTime();
|
||||
|
||||
if ( t != 0 )
|
||||
{
|
||||
struct tm structuredTime;
|
||||
|
||||
Plat_localtime(&t, &structuredTime);
|
||||
|
||||
year = structuredTime.tm_year + 1900;
|
||||
month = structuredTime.tm_mon + 1; // 0..11
|
||||
day = structuredTime.tm_mday;
|
||||
hour = structuredTime.tm_hour;
|
||||
minute = structuredTime.tm_min;
|
||||
second = structuredTime.tm_sec;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CCSBaseAchievement::GetSettings( KeyValues* pNodeOut )
|
||||
{
|
||||
BaseClass::GetSettings(pNodeOut);
|
||||
|
||||
pNodeOut->SetInt("unlockTime", GetUnlockTime());
|
||||
}
|
||||
|
||||
void CCSBaseAchievement::ApplySettings( /* const */ KeyValues* pNodeIn )
|
||||
{
|
||||
BaseClass::ApplySettings(pNodeIn);
|
||||
|
||||
SetUnlockTime(pNodeIn->GetInt("unlockTime"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Meta Achievement base class methods
|
||||
*/
|
||||
CAchievement_Meta::CAchievement_Meta() :
|
||||
m_CallbackUserAchievement( this, &CAchievement_Meta::Steam_OnUserAchievementStored )
|
||||
{
|
||||
}
|
||||
|
||||
void CAchievement_Meta::Init()
|
||||
{
|
||||
SetFlags( ACH_SAVE_GLOBAL );
|
||||
SetGoal( 1 );
|
||||
}
|
||||
|
||||
void CAchievement_Meta::Steam_OnUserAchievementStored( UserAchievementStored_t *pUserAchievementStored )
|
||||
{
|
||||
if ( IsAchieved() )
|
||||
return;
|
||||
|
||||
int iAchieved = 0;
|
||||
|
||||
FOR_EACH_VEC(m_requirements, i)
|
||||
{
|
||||
IAchievement* pAchievement = (IAchievement*)m_pAchievementMgr->GetAchievementByID(m_requirements[i]);
|
||||
Assert ( pAchievement );
|
||||
|
||||
if ( pAchievement->IsAchieved() )
|
||||
iAchieved++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if ( iAchieved == m_requirements.Count() )
|
||||
{
|
||||
AwardAchievement();
|
||||
}
|
||||
}
|
||||
|
||||
void CAchievement_Meta::AddRequirement( int nAchievementId )
|
||||
{
|
||||
m_requirements.AddToTail(nAchievementId);
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool CheckWinNoEnemyCaps( IGameEvent *event, int iRole );
|
||||
|
||||
// Grace period that we allow a player to start after level init and still consider them to be participating for the full round. This is fairly generous
|
||||
// because it can in some cases take a client several minutes to connect with respect to when the server considers the game underway
|
||||
#define CS_FULL_ROUND_GRACE_PERIOD ( 4 * 60.0f )
|
||||
|
||||
bool IsLocalCSPlayerClass( int iClass );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCSBaseAchievementFullRound::Init()
|
||||
{
|
||||
m_iFlags |= ACH_FILTER_FULL_ROUND_ONLY;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCSBaseAchievementFullRound::ListenForEvents()
|
||||
{
|
||||
ListenForGameEvent( "teamplay_round_win" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCSBaseAchievementFullRound::FireGameEvent_Internal( IGameEvent *event )
|
||||
{
|
||||
if ( 0 == Q_strcmp( event->GetName(), "teamplay_round_win" ) )
|
||||
{
|
||||
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
if ( pLocalPlayer )
|
||||
{
|
||||
// is the player currently on a game team?
|
||||
int iTeam = pLocalPlayer->GetTeamNumber();
|
||||
if ( iTeam >= FIRST_GAME_TEAM )
|
||||
{
|
||||
float flRoundTime = event->GetFloat( "round_time", 0 );
|
||||
if ( flRoundTime > 0 )
|
||||
{
|
||||
Event_OnRoundComplete( flRoundTime, event );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CCSBaseAchievementFullRound::PlayerWasInEntireRound( float flRoundTime )
|
||||
{
|
||||
float flTeamplayStartTime = m_pAchievementMgr->GetTeamplayStartTime();
|
||||
if ( flTeamplayStartTime > 0 )
|
||||
{
|
||||
// has the player been present and on a game team since the start of this round (minus a grace period)?
|
||||
if ( flTeamplayStartTime < ( gpGlobals->curtime - flRoundTime ) + CS_FULL_ROUND_GRACE_PERIOD )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
//Base class for all achievements to kill x players with a given weapon
|
||||
class CAchievement_StatGoal: public CCSBaseAchievement
|
||||
{
|
||||
public:
|
||||
void SetStatId(CSStatType_t stat)
|
||||
{
|
||||
m_StatId = stat;
|
||||
}
|
||||
private:
|
||||
virtual void Init()
|
||||
{
|
||||
SetFlags( ACH_SAVE_GLOBAL );
|
||||
}
|
||||
|
||||
void OnPlayerStatsUpdate()
|
||||
{
|
||||
// when stats are updated by server, use most recent stat value
|
||||
const StatsCollection_t& roundStats = g_CSClientGameStats.GetLifetimeStats();
|
||||
|
||||
int iOldCount = GetCount();
|
||||
SetCount(roundStats[m_StatId]);
|
||||
if ( GetCount() != iOldCount )
|
||||
{
|
||||
m_pAchievementMgr->SetDirty(true);
|
||||
}
|
||||
|
||||
int iGoal = GetGoal();
|
||||
if (!IsAchieved() && iGoal > 0 )
|
||||
{
|
||||
if (achievements_easymode.GetBool())
|
||||
{
|
||||
iGoal /= 10;
|
||||
if ( iGoal == 0 )
|
||||
iGoal = 1;
|
||||
}
|
||||
|
||||
if ( GetCount() >= iGoal )
|
||||
{
|
||||
AwardAchievement();
|
||||
}
|
||||
}
|
||||
}
|
||||
CSStatType_t m_StatId;
|
||||
};
|
||||
|
||||
#define DECLARE_ACHIEVEMENT_STATGOAL( achievementID, achievementName, iPointValue, iStatId, iGoal ) \
|
||||
static CBaseAchievement *Create_##achievementID( void ) \
|
||||
{ \
|
||||
CAchievement_StatGoal *pAchievement = new CAchievement_StatGoal(); \
|
||||
pAchievement->SetAchievementID( achievementID ); \
|
||||
pAchievement->SetName( achievementName ); \
|
||||
pAchievement->SetPointValue( iPointValue ); \
|
||||
pAchievement->SetHideUntilAchieved( false ); \
|
||||
pAchievement->SetStatId(iStatId); \
|
||||
pAchievement->SetGoal( iGoal ); \
|
||||
return pAchievement; \
|
||||
}; \
|
||||
static CBaseAchievementHelper g_##achievementID##_Helper( Create_##achievementID );
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsLow, "KILL_ENEMY_LOW", 10, CSSTAT_KILLS, 25); //25
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsMed, "KILL_ENEMY_MED", 10, CSSTAT_KILLS, 500); //500
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsHigh, "KILL_ENEMY_HIGH", 10, CSSTAT_KILLS, 10000); //10000
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinRoundsLow, "WIN_ROUNDS_LOW", 10, CSSTAT_ROUNDS_WON, 10); //10
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinRoundsMed, "WIN_ROUNDS_MED", 10, CSSTAT_ROUNDS_WON, 200); //200
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinRoundsHigh, "WIN_ROUNDS_HIGH", 10, CSSTAT_ROUNDS_WON, 5000); //5000
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinPistolRoundsLow, "WIN_PISTOLROUNDS_LOW", 10, CSSTAT_PISTOLROUNDS_WON, 5); //5
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinPistolRoundsMed, "WIN_PISTOLROUNDS_MED", 10, CSSTAT_PISTOLROUNDS_WON, 25); //25
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinPistolRoundsHigh, "WIN_PISTOLROUNDS_HIGH", 10, CSSTAT_PISTOLROUNDS_WON, 250); //250
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSMoneyEarnedLow, "EARN_MONEY_LOW", 10, CSSTAT_MONEY_EARNED, 125000); //125000
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSMoneyEarnedMed, "EARN_MONEY_MED", 10, CSSTAT_MONEY_EARNED, 2500000); //2500000
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSMoneyEarnedHigh, "EARN_MONEY_HIGH", 10, CSSTAT_MONEY_EARNED, 50000000); //50000000
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSGiveDamageLow, "GIVE_DAMAGE_LOW", 10, CSSTAT_DAMAGE, 2500); //2500
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSGiveDamageMed, "GIVE_DAMAGE_MED", 10, CSSTAT_DAMAGE, 50000); //50000
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSGiveDamageHigh, "GIVE_DAMAGE_HIGH", 10, CSSTAT_DAMAGE, 1000000); //1000000
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsDeagle, "KILL_ENEMY_DEAGLE", 5, CSSTAT_KILLS_DEAGLE, 200); //200
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsUSP, "KILL_ENEMY_USP", 5, CSSTAT_KILLS_USP, 200); //200
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsGlock, "KILL_ENEMY_GLOCK", 5, CSSTAT_KILLS_GLOCK, 200); //200
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsP228, "KILL_ENEMY_P228", 5, CSSTAT_KILLS_P228, 200); //200
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsElite, "KILL_ENEMY_ELITE", 5, CSSTAT_KILLS_ELITE, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsFiveSeven, "KILL_ENEMY_FIVESEVEN", 5, CSSTAT_KILLS_FIVESEVEN, 100); //100
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsAWP, "KILL_ENEMY_AWP", 5, CSSTAT_KILLS_AWP, 1000); //1000
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsAK47, "KILL_ENEMY_AK47", 5, CSSTAT_KILLS_AK47, 1000); //1000
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsM4A1, "KILL_ENEMY_M4A1", 5, CSSTAT_KILLS_M4A1, 1000); //1000
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsAUG, "KILL_ENEMY_AUG", 5, CSSTAT_KILLS_AUG, 500); //500
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsSG552, "KILL_ENEMY_SG552", 5, CSSTAT_KILLS_SG552, 500); //500
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsSG550, "KILL_ENEMY_SG550", 5, CSSTAT_KILLS_SG550, 500); //500
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsGALIL, "KILL_ENEMY_GALIL", 5, CSSTAT_KILLS_GALIL, 500); //500
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsFAMAS, "KILL_ENEMY_FAMAS", 5, CSSTAT_KILLS_FAMAS, 500); //500
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsScout, "KILL_ENEMY_SCOUT", 5, CSSTAT_KILLS_SCOUT, 1000); //1000
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsG3SG1, "KILL_ENEMY_G3SG1", 5, CSSTAT_KILLS_G3SG1, 500); //500
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsP90, "KILL_ENEMY_P90", 5, CSSTAT_KILLS_P90, 1000); //1000
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsMP5NAVY, "KILL_ENEMY_MP5NAVY", 5, CSSTAT_KILLS_MP5NAVY, 1000); //1000
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsTMP, "KILL_ENEMY_TMP", 5, CSSTAT_KILLS_TMP, 500); //500
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsMAC10, "KILL_ENEMY_MAC10", 5, CSSTAT_KILLS_MAC10, 500); //500
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsUMP45, "KILL_ENEMY_UMP45", 5, CSSTAT_KILLS_UMP45, 1000); //1000
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsM3, "KILL_ENEMY_M3", 5, CSSTAT_KILLS_M3, 200); //200
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsXM1014, "KILL_ENEMY_XM1014", 5, CSSTAT_KILLS_XM1014, 200); //200
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsM249, "KILL_ENEMY_M249", 5, CSSTAT_KILLS_M249, 500); //500
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsKnife, "KILL_ENEMY_KNIFE", 5, CSSTAT_KILLS_KNIFE, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSEnemyKillsHEGrenade, "KILL_ENEMY_HEGRENADE", 5, CSSTAT_KILLS_HEGRENADE, 500); //500
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSHeadshots, "HEADSHOTS", 5, CSSTAT_KILLS_HEADSHOT, 250); //250
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSKillsEnemyWeapon, "KILLS_ENEMY_WEAPON", 5, CSSTAT_KILLS_ENEMY_WEAPON, 100); //100
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSKillEnemyBlinded, "KILL_ENEMY_BLINDED", 5, CSSTAT_KILLS_ENEMY_BLINDED, 25); //25
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSDefuseBombsLow, "BOMB_DEFUSE_LOW", 5, CSSTAT_NUM_BOMBS_DEFUSED, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSPlantBombsLow, "BOMB_PLANT_LOW", 5, CSSTAT_NUM_BOMBS_PLANTED, 100); //100
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSRescueHostagesLow, "RESCUE_HOSTAGES_LOW", 5, CSSTAT_NUM_HOSTAGES_RESCUED, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSRescueHostagesMid, "RESCUE_HOSTAGES_MED", 5, CSSTAT_NUM_HOSTAGES_RESCUED, 500); //500
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinKnifeFightsLow, "WIN_KNIFE_FIGHTS_LOW", 5, CSSTAT_KILLS_KNIFE_FIGHT, 1); //1
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinKnifeFightsHigh, "WIN_KNIFE_FIGHTS_HIGH", 5, CSSTAT_KILLS_KNIFE_FIGHT, 100); //100
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSDecalSprays, "DECAL_SPRAYS", 5, CSSTAT_DECAL_SPRAYS, 100); //100
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSNightvisionDamage, "NIGHTVISION_DAMAGE", 5, CSSTAT_NIGHTVISION_DAMAGE, 5000); //5000
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSKillSnipers, "KILL_SNIPERS", 5, CSSTAT_KILLS_AGAINST_ZOOMED_SNIPER, 100); //100
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapCS_ASSAULT, "WIN_MAP_CS_ASSAULT", 5, CSSTAT_MAP_WINS_CS_ASSAULT, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapCS_COMPOUND, "WIN_MAP_CS_COMPOUND", 5, CSSTAT_MAP_WINS_CS_COMPOUND, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapCS_HAVANA, "WIN_MAP_CS_HAVANA", 5, CSSTAT_MAP_WINS_CS_HAVANA, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapCS_ITALY, "WIN_MAP_CS_ITALY", 5, CSSTAT_MAP_WINS_CS_ITALY, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapCS_MILITIA, "WIN_MAP_CS_MILITIA", 5, CSSTAT_MAP_WINS_CS_MILITIA, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapCS_OFFICE, "WIN_MAP_CS_OFFICE", 5, CSSTAT_MAP_WINS_CS_OFFICE, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapDE_AZTEC, "WIN_MAP_DE_AZTEC", 5, CSSTAT_MAP_WINS_DE_AZTEC, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapDE_CBBLE, "WIN_MAP_DE_CBBLE", 5, CSSTAT_MAP_WINS_DE_CBBLE, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapDE_CHATEAU, "WIN_MAP_DE_CHATEAU", 5, CSSTAT_MAP_WINS_DE_CHATEAU, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapDE_DUST2, "WIN_MAP_DE_DUST2", 5, CSSTAT_MAP_WINS_DE_DUST2, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapDE_DUST, "WIN_MAP_DE_DUST", 5, CSSTAT_MAP_WINS_DE_DUST, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapDE_INFERNO, "WIN_MAP_DE_INFERNO", 5, CSSTAT_MAP_WINS_DE_INFERNO, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapDE_NUKE, "WIN_MAP_DE_NUKE", 5, CSSTAT_MAP_WINS_DE_NUKE, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapDE_PIRANESI, "WIN_MAP_DE_PIRANESI", 5, CSSTAT_MAP_WINS_DE_PIRANESI, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapDE_PORT, "WIN_MAP_DE_PORT", 5, CSSTAT_MAP_WINS_DE_PORT, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapDE_PRODIGY, "WIN_MAP_DE_PRODIGY", 5, CSSTAT_MAP_WINS_DE_PRODIGY, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapDE_TIDES, "WIN_MAP_DE_TIDES", 5, CSSTAT_MAP_WINS_DE_TIDES, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSWinMapDE_TRAIN, "WIN_MAP_DE_TRAIN", 5, CSSTAT_MAP_WINS_DE_TRAIN, 100); //100
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSDonateWeapons, "DONATE_WEAPONS", 5, CSSTAT_WEAPONS_DONATED, 100); //100
|
||||
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSDominationsLow, "DOMINATIONS_LOW", 5, CSSTAT_DOMINATIONS, 1); //1
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSDominationsHigh, "DOMINATIONS_HIGH", 5, CSSTAT_DOMINATIONS, 10); //10
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSDominationOverkillsLow, "DOMINATION_OVERKILLS_LOW", 5, CSSTAT_DOMINATION_OVERKILLS, 1); //1
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSDominationOverkillsHigh, "DOMINATION_OVERKILLS_HIGH",5, CSSTAT_DOMINATION_OVERKILLS, 100); //100
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSRevengesLow, "REVENGES_LOW", 5, CSSTAT_REVENGES, 1); //1
|
||||
DECLARE_ACHIEVEMENT_STATGOAL(CSRevengesHigh, "REVENGES_HIGH", 5, CSSTAT_REVENGES, 20); //20
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Generic server awarded achievement
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAchievementCS_ServerAwarded : public CCSBaseAchievement
|
||||
{
|
||||
virtual void Init()
|
||||
{
|
||||
SetGoal(1);
|
||||
SetFlags( ACH_SAVE_GLOBAL );
|
||||
}
|
||||
|
||||
// server fires an event for this achievement, no other code within achievement necessary
|
||||
};
|
||||
|
||||
#define DECLARE_ACHIEVEMENT_SERVERAWARDED(achievementID, achievementName, iPointValue) \
|
||||
static CBaseAchievement *Create_##achievementID( void ) \
|
||||
{ \
|
||||
CAchievementCS_ServerAwarded *pAchievement = new CAchievementCS_ServerAwarded( ); \
|
||||
pAchievement->SetAchievementID( achievementID ); \
|
||||
pAchievement->SetName( achievementName ); \
|
||||
pAchievement->SetPointValue( iPointValue ); \
|
||||
return pAchievement; \
|
||||
}; \
|
||||
static CBaseAchievementHelper g_##achievementID##_Helper( Create_##achievementID );
|
||||
|
||||
|
||||
|
||||
// server triggered achievements
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSBombDefuseCloseCall, "BOMB_DEFUSE_CLOSE_CALL", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSDefuseAndNeededKit, "BOMB_DEFUSE_NEEDED_KIT", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKilledDefuser, "KILL_BOMB_DEFUSER", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSWinBombPlant, "WIN_BOMB_PLANT", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSWinBombDefuse, "WIN_BOMB_DEFUSE", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSPlantBombWithin25Seconds, "BOMB_PLANT_IN_25_SECONDS", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSRescueAllHostagesInARound, "RESCUE_ALL_HOSTAGES", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillEnemyWithFormerGun, "KILL_WITH_OWN_GUN", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillingSpree, "KILLING_SPREE", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillTwoWithOneShot, "KILL_TWO_WITH_ONE_SHOT", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillEnemyReloading, "KILL_ENEMY_RELOADING", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillsWithMultipleGuns, "KILLS_WITH_MULTIPLE_GUNS", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSPosthumousGrenadeKill, "DEAD_GRENADE_KILL", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillEnemyTeam, "KILL_ENEMY_TEAM", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSLastPlayerAlive, "LAST_PLAYER_ALIVE", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillEnemyLastBullet, "KILL_ENEMY_LAST_BULLET", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillingSpreeEnder, "KILLING_SPREE_ENDER", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillEnemiesWhileBlind, "KILL_ENEMIES_WHILE_BLIND", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillEnemiesWhileBlindHard, "KILL_ENEMIES_WHILE_BLIND_HARD", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSDamageNoKill, "DAMAGE_NO_KILL", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillLowDamage, "KILL_LOW_DAMAGE", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKilledRescuer, "KILL_HOSTAGE_RESCUER", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSSurviveGrenade, "SURVIVE_GRENADE", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKilledDefuserWithGrenade, "KILLED_DEFUSER_WITH_GRENADE", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSSurvivedHeadshotDueToHelmet, "SURVIVED_HEADSHOT_DUE_TO_HELMET", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillSniperWithSniper, "KILL_SNIPER_WITH_SNIPER", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillSniperWithKnife, "KILL_SNIPER_WITH_KNIFE", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSHipShot, "HIP_SHOT", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillWhenAtLowHealth, "KILL_WHEN_AT_LOW_HEALTH", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSGrenadeMultikill, "GRENADE_MULTIKILL", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSBombMultikill, "BOMB_MULTIKILL", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSPistolRoundKnifeKill, "PISTOL_ROUND_KNIFE_KILL", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSFastRoundWin, "FAST_ROUND_WIN", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSSurviveManyAttacks, "SURVIVE_MANY_ATTACKS", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSGooseChase, "GOOSE_CHASE", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSWinBombPlantAfterRecovery, "WIN_BOMB_PLANT_AFTER_RECOVERY", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSLosslessExtermination, "LOSSLESS_EXTERMINATION", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSFlawlessVictory, "FLAWLESS_VICTORY", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSWinDualDuel, "WIN_DUAL_DUEL", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSFastHostageRescue, "FAST_HOSTAGE_RESCUE", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSBreakWindows, "BREAK_WINDOWS", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSBreakProps, "BREAK_PROPS", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSUnstoppableForce, "UNSTOPPABLE_FORCE", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSImmovableObject, "IMMOVABLE_OBJECT", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSHeadshotsInRound, "HEADSHOTS_IN_ROUND", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillWhileInAir, "KILL_WHILE_IN_AIR", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillEnemyInAir, "KILL_ENEMY_IN_AIR", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillerAndEnemyInAir, "KILLER_AND_ENEMY_IN_AIR", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSSilentWin, "SILENT_WIN", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSBloodlessVictory, "BLOODLESS_VICTORY", 5);
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSWinRoundsWithoutBuying, "WIN_ROUNDS_WITHOUT_BUYING", 5)
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSDefuseDefense, "DEFUSE_DEFENSE", 5)
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSKillBombPickup, "KILL_BOMB_PICKUP", 5)
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSSameUniform, "SAME_UNIFORM", 5)
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSConcurrentDominations, "CONCURRENT_DOMINATIONS", 5)
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSDominationOverkillsMatch, "DOMINATION_OVERKILLS_MATCH", 5)
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSExtendedDomination, "EXTENDED_DOMINATION", 5)
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSCauseFriendlyFireWithFlashbang, "CAUSE_FRIENDLY_FIRE_WITH_FLASHBANG", 5)
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSWinClanMatch, "WIN_CLAN_MATCH", 5)
|
||||
DECLARE_ACHIEVEMENT_SERVERAWARDED(CSSnipeTwoFromSameSpot, "SNIPE_TWO_FROM_SAME_SPOT", 5 )
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Meta Achievements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get all the pistol achievements
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAchievementCS_PistolMaster : public CAchievement_Meta
|
||||
{
|
||||
DECLARE_CLASS( CAchievementCS_PistolMaster, CAchievement_Meta );
|
||||
virtual void Init()
|
||||
{
|
||||
BaseClass::Init();
|
||||
AddRequirement(CSEnemyKillsDeagle);
|
||||
AddRequirement(CSEnemyKillsUSP);
|
||||
AddRequirement(CSEnemyKillsGlock);
|
||||
AddRequirement(CSEnemyKillsP228);
|
||||
AddRequirement(CSEnemyKillsElite);
|
||||
AddRequirement(CSEnemyKillsFiveSeven);
|
||||
}
|
||||
};
|
||||
DECLARE_ACHIEVEMENT(CAchievementCS_PistolMaster, CSMetaPistol, "META_PISTOL", 10);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get all the rifle achievements
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAchievementCS_RifleMaster : public CAchievement_Meta
|
||||
{
|
||||
DECLARE_CLASS( CAchievementCS_RifleMaster, CAchievement_Meta );
|
||||
virtual void Init()
|
||||
{
|
||||
BaseClass::Init();
|
||||
AddRequirement(CSEnemyKillsAWP);
|
||||
AddRequirement(CSEnemyKillsAK47);
|
||||
AddRequirement(CSEnemyKillsM4A1);
|
||||
AddRequirement(CSEnemyKillsAUG);
|
||||
AddRequirement(CSEnemyKillsSG552);
|
||||
AddRequirement(CSEnemyKillsSG550);
|
||||
AddRequirement(CSEnemyKillsGALIL);
|
||||
AddRequirement(CSEnemyKillsFAMAS);
|
||||
AddRequirement(CSEnemyKillsScout);
|
||||
AddRequirement(CSEnemyKillsG3SG1);
|
||||
}
|
||||
};
|
||||
DECLARE_ACHIEVEMENT(CAchievementCS_RifleMaster, CSMetaRifle, "META_RIFLE", 10);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get all the SMG achievements
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAchievementCS_SubMachineGunMaster : public CAchievement_Meta
|
||||
{
|
||||
DECLARE_CLASS( CAchievementCS_SubMachineGunMaster, CAchievement_Meta );
|
||||
virtual void Init()
|
||||
{
|
||||
BaseClass::Init();
|
||||
AddRequirement(CSEnemyKillsP90);
|
||||
AddRequirement(CSEnemyKillsMP5NAVY);
|
||||
AddRequirement(CSEnemyKillsTMP);
|
||||
AddRequirement(CSEnemyKillsMAC10);
|
||||
AddRequirement(CSEnemyKillsUMP45);
|
||||
}
|
||||
};
|
||||
DECLARE_ACHIEVEMENT(CAchievementCS_SubMachineGunMaster, CSMetaSMG, "META_SMG", 10);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get all the Shotgun achievements
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAchievementCS_ShotgunMaster : public CAchievement_Meta
|
||||
{
|
||||
DECLARE_CLASS( CAchievementCS_ShotgunMaster, CAchievement_Meta );
|
||||
virtual void Init()
|
||||
{
|
||||
BaseClass::Init();
|
||||
AddRequirement(CSEnemyKillsM3);
|
||||
AddRequirement(CSEnemyKillsXM1014);
|
||||
}
|
||||
};
|
||||
DECLARE_ACHIEVEMENT(CAchievementCS_ShotgunMaster, CSMetaShotgun, "META_SHOTGUN", 10);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get every weapon achievement
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAchievementCS_WeaponMaster : public CAchievement_Meta
|
||||
{
|
||||
DECLARE_CLASS( CAchievementCS_WeaponMaster, CAchievement_Meta );
|
||||
virtual void Init()
|
||||
{
|
||||
BaseClass::Init();
|
||||
AddRequirement(CSMetaPistol);
|
||||
AddRequirement(CSMetaRifle);
|
||||
AddRequirement(CSMetaSMG);
|
||||
AddRequirement(CSMetaShotgun);
|
||||
AddRequirement(CSEnemyKillsM249);
|
||||
AddRequirement(CSEnemyKillsKnife);
|
||||
AddRequirement(CSEnemyKillsHEGrenade);
|
||||
}
|
||||
};
|
||||
DECLARE_ACHIEVEMENT(CAchievementCS_WeaponMaster, CSMetaWeaponMaster, "META_WEAPONMASTER", 50);
|
||||
|
||||
|
||||
|
||||
class CAchievementCS_KillWithAllWeapons : public CCSBaseAchievement
|
||||
{
|
||||
void Init()
|
||||
{
|
||||
SetFlags( ACH_SAVE_GLOBAL );
|
||||
SetGoal( 1 );
|
||||
}
|
||||
|
||||
void OnPlayerStatsUpdate()
|
||||
{
|
||||
const StatsCollection_t& roundStats = g_CSClientGameStats.GetLifetimeStats();
|
||||
|
||||
//Loop through all weapons we care about and make sure we got a kill with each.
|
||||
for (int i = 0; WeaponName_StatId_Table[i].killStatId != CSSTAT_UNDEFINED; ++i)
|
||||
{
|
||||
CSStatType_t statId = WeaponName_StatId_Table[i].killStatId;
|
||||
|
||||
if ( roundStats[statId] == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//If we haven't bailed yet, award the achievement.
|
||||
IncrementCount();
|
||||
}
|
||||
};
|
||||
DECLARE_ACHIEVEMENT( CAchievementCS_KillWithAllWeapons, CSKillWithEveryWeapon, "KILL_WITH_EVERY_WEAPON", 5 );
|
||||
|
||||
class CAchievementCS_FriendsSameUniform : public CCSBaseAchievement
|
||||
{
|
||||
void Init()
|
||||
{
|
||||
SetFlags(ACH_SAVE_GLOBAL);
|
||||
SetGoal(1);
|
||||
}
|
||||
|
||||
void ListenForEvents()
|
||||
{
|
||||
ListenForGameEvent( "round_start" );
|
||||
}
|
||||
|
||||
void FireGameEvent_Internal( IGameEvent *event )
|
||||
{
|
||||
if ( Q_strcmp( event->GetName(), "round_start" ) == 0 )
|
||||
{
|
||||
int localPlayerIndex = GetLocalPlayerIndex();
|
||||
C_CSPlayer* pLocalPlayer = ToCSPlayer(UTIL_PlayerByIndex(localPlayerIndex));
|
||||
|
||||
// Initialize all to 1, since the local player doesn't get counted as we loop.
|
||||
int numPlayersOnTeam = 1;
|
||||
int numFriendsOnTeam = 1;
|
||||
int numMatchingFriendsOnTeam = 1;
|
||||
|
||||
if (pLocalPlayer)
|
||||
{
|
||||
int localPlayerClass = pLocalPlayer->PlayerClass();
|
||||
int localPlayerTeam = pLocalPlayer->GetTeamNumber();
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
if ( i != localPlayerIndex)
|
||||
{
|
||||
CCSPlayer *pPlayer = (CCSPlayer*) UTIL_PlayerByIndex( i );
|
||||
|
||||
if (pPlayer)
|
||||
{
|
||||
if (pPlayer->GetTeamNumber() == localPlayerTeam)
|
||||
{
|
||||
++numPlayersOnTeam;
|
||||
if (pLocalPlayer->HasPlayerAsFriend(pPlayer) )
|
||||
{
|
||||
++numFriendsOnTeam;
|
||||
if ( pPlayer->PlayerClass() == localPlayerClass )
|
||||
++numMatchingFriendsOnTeam;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numMatchingFriendsOnTeam >= AchievementConsts::FriendsSameUniform_MinPlayers )
|
||||
{
|
||||
AwardAchievement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
DECLARE_ACHIEVEMENT( CAchievementCS_FriendsSameUniform, CSFriendsSameUniform, "FRIENDS_SAME_UNIFORM", 5 );
|
||||
|
||||
|
||||
|
||||
class CAchievementCS_AvengeFriend : public CCSBaseAchievement
|
||||
{
|
||||
void Init()
|
||||
{
|
||||
SetFlags(ACH_SAVE_GLOBAL);
|
||||
SetGoal(1);
|
||||
}
|
||||
|
||||
void ListenForEvents()
|
||||
{
|
||||
ListenForGameEvent( "player_avenged_teammate" );
|
||||
}
|
||||
|
||||
void FireGameEvent_Internal( IGameEvent *event )
|
||||
{
|
||||
if ( Q_strcmp( event->GetName(), "player_avenged_teammate" ) == 0 )
|
||||
{
|
||||
int localPlayerIndex = GetLocalPlayerIndex();
|
||||
C_CSPlayer* pLocalPlayer = ToCSPlayer(UTIL_PlayerByIndex(localPlayerIndex));
|
||||
|
||||
//for debugging
|
||||
//int eventId = event->GetInt( "avenger_id" );
|
||||
//int localUserId = pLocalPlayer->GetUserID();
|
||||
|
||||
if (pLocalPlayer && pLocalPlayer->GetUserID() == event->GetInt( "avenger_id" ))
|
||||
{
|
||||
int avengedPlayerIndex = engine->GetPlayerForUserID( event->GetInt( "avenged_player_id" ) );
|
||||
|
||||
if ( avengedPlayerIndex > 0 )
|
||||
{
|
||||
C_CSPlayer* pAvengedPlayer = ToCSPlayer(UTIL_PlayerByIndex(avengedPlayerIndex));
|
||||
if (pAvengedPlayer && pLocalPlayer->HasPlayerAsFriend(pAvengedPlayer))
|
||||
{
|
||||
AwardAchievement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
DECLARE_ACHIEVEMENT( CAchievementCS_AvengeFriend, CSAvengeFriend, "AVENGE_FRIEND", 5 );
|
||||
|
||||
|
||||
|
||||
class CAchievementCS_CollectHolidayGifts : public CCSBaseAchievement
|
||||
{
|
||||
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( 3 /*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_CSPlayer::GetLocalCSPlayer() )
|
||||
{
|
||||
IncrementCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
DECLARE_ACHIEVEMENT( CAchievementCS_CollectHolidayGifts, CSCollectHolidayGifts, "COLLECT_GIFTS", 5 );
|
||||
|
||||
#endif // CLIENT_DLL
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
bool CheckWinNoEnemyCaps( IGameEvent *event, int iRole );
|
||||
bool IsLocalCSPlayerClass( int iClass );
|
||||
bool GameRulesAllowsAchievements( void );
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------
|
||||
// Base class for all CS achievements
|
||||
class CCSBaseAchievement : public CBaseAchievement
|
||||
{
|
||||
DECLARE_CLASS( CCSBaseAchievement, CBaseAchievement );
|
||||
public:
|
||||
|
||||
CCSBaseAchievement();
|
||||
|
||||
virtual void GetSettings( KeyValues* pNodeOut ); // serialize
|
||||
virtual void ApplySettings( /* const */ KeyValues* pNodeIn ); // unserialize
|
||||
|
||||
// [dwenger] Necessary for sorting achievements by award time
|
||||
virtual void OnAchieved();
|
||||
bool GetAwardTime( int& year, int& month, int& day, int& hour, int& minute, int& second );
|
||||
|
||||
int64 GetSortKey() const { return GetUnlockTime(); }
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------
|
||||
// Helper class for achievements that check that the player was playing on a game team for the full round
|
||||
class CCSBaseAchievementFullRound : public CCSBaseAchievement
|
||||
{
|
||||
DECLARE_CLASS( CCSBaseAchievementFullRound, CCSBaseAchievement );
|
||||
public:
|
||||
virtual void Init() ;
|
||||
virtual void ListenForEvents();
|
||||
void FireGameEvent_Internal( IGameEvent *event );
|
||||
bool PlayerWasInEntireRound( float flRoundTime );
|
||||
|
||||
virtual void Event_OnRoundComplete( float flRoundTime, IGameEvent *event ) = 0 ;
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------
|
||||
// Helper class for achievements based on other achievements
|
||||
class CAchievement_Meta : public CCSBaseAchievement
|
||||
{
|
||||
DECLARE_CLASS( CAchievement_Meta, CCSBaseAchievement );
|
||||
public:
|
||||
CAchievement_Meta();
|
||||
virtual void Init();
|
||||
|
||||
#if !defined(NO_STEAM)
|
||||
STEAM_CALLBACK( CAchievement_Meta, Steam_OnUserAchievementStored, UserAchievementStored_t, m_CallbackUserAchievement );
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void AddRequirement( int nAchievementId );
|
||||
|
||||
private:
|
||||
CUtlVector<int> m_requirements;
|
||||
};
|
||||
|
||||
|
||||
|
||||
extern CAchievementMgr g_AchievementMgrCS; // global achievement mgr for CS
|
||||
|
||||
#endif // CLIENT_DLL
|
||||
@@ -0,0 +1,346 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "basecsgrenade_projectile.h"
|
||||
|
||||
float GetCurrentGravity( void );
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "bot_manager.h"
|
||||
#include "cs_player.h"
|
||||
#include "soundent.h"
|
||||
#include "te_effect_dispatch.h"
|
||||
#include "KeyValues.h"
|
||||
|
||||
BEGIN_DATADESC( CBaseCSGrenadeProjectile )
|
||||
DEFINE_THINKFUNC( DangerSoundThink ),
|
||||
END_DATADESC()
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( BaseCSGrenadeProjectile, DT_BaseCSGrenadeProjectile )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CBaseCSGrenadeProjectile, DT_BaseCSGrenadeProjectile )
|
||||
#ifdef CLIENT_DLL
|
||||
RecvPropVector( RECVINFO( m_vInitialVelocity ) )
|
||||
#else
|
||||
SendPropVector( SENDINFO( m_vInitialVelocity ),
|
||||
20, // nbits
|
||||
0, // flags
|
||||
-3000, // low value
|
||||
3000 // high value
|
||||
)
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
|
||||
void CBaseCSGrenadeProjectile::PostDataUpdate( DataUpdateType_t type )
|
||||
{
|
||||
BaseClass::PostDataUpdate( type );
|
||||
|
||||
if ( type == DATA_UPDATE_CREATED )
|
||||
{
|
||||
// Now stick our initial velocity into the interpolation history
|
||||
CInterpolatedVar< Vector > &interpolator = GetOriginInterpolator();
|
||||
|
||||
interpolator.ClearHistory();
|
||||
float changeTime = GetLastChangeTime( LATCH_SIMULATION_VAR );
|
||||
|
||||
// Add a sample 1 second back.
|
||||
Vector vCurOrigin = GetLocalOrigin() - m_vInitialVelocity;
|
||||
interpolator.AddToHead( changeTime - 1.0, &vCurOrigin, false );
|
||||
|
||||
// Add the current sample.
|
||||
vCurOrigin = GetLocalOrigin();
|
||||
interpolator.AddToHead( changeTime, &vCurOrigin, false );
|
||||
}
|
||||
}
|
||||
|
||||
int CBaseCSGrenadeProjectile::DrawModel( int flags )
|
||||
{
|
||||
// During the first half-second of our life, don't draw ourselves if he's
|
||||
// still playing his throw animation.
|
||||
// (better yet, we could draw ourselves in his hand).
|
||||
if ( GetThrower() != C_BasePlayer::GetLocalPlayer() )
|
||||
{
|
||||
if ( gpGlobals->curtime - m_flSpawnTime < 0.5 )
|
||||
{
|
||||
C_CSPlayer *pPlayer = dynamic_cast<C_CSPlayer*>( GetThrower() );
|
||||
if ( pPlayer && pPlayer->m_PlayerAnimState->IsThrowingGrenade() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BaseClass::DrawModel( flags );
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::Spawn()
|
||||
{
|
||||
m_flSpawnTime = gpGlobals->curtime;
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void CBaseCSGrenadeProjectile::PostConstructor( const char *className )
|
||||
{
|
||||
BaseClass::PostConstructor( className );
|
||||
TheBots->AddGrenade( this );
|
||||
}
|
||||
|
||||
CBaseCSGrenadeProjectile::~CBaseCSGrenadeProjectile()
|
||||
{
|
||||
TheBots->RemoveGrenade( this );
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::Spawn( void )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
|
||||
SetSolidFlags( FSOLID_NOT_STANDABLE );
|
||||
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM );
|
||||
SetSolid( SOLID_BBOX ); // So it will collide with physics props!
|
||||
|
||||
// smaller, cube bounding box so we rest on the ground
|
||||
SetSize( Vector ( -2, -2, -2 ), Vector ( 2, 2, 2 ) );
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::DangerSoundThink( void )
|
||||
{
|
||||
if (!IsInWorld())
|
||||
{
|
||||
Remove( );
|
||||
return;
|
||||
}
|
||||
|
||||
if( gpGlobals->curtime > m_flDetonateTime )
|
||||
{
|
||||
Detonate();
|
||||
return;
|
||||
}
|
||||
|
||||
CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin() + GetAbsVelocity() * 0.5, GetAbsVelocity().Length( ), 0.2 );
|
||||
|
||||
SetNextThink( gpGlobals->curtime + 0.2 );
|
||||
|
||||
if (GetWaterLevel() != 0)
|
||||
{
|
||||
SetAbsVelocity( GetAbsVelocity() * 0.5 );
|
||||
}
|
||||
}
|
||||
|
||||
//Sets the time at which the grenade will explode
|
||||
void CBaseCSGrenadeProjectile::SetDetonateTimerLength( float timer )
|
||||
{
|
||||
m_flDetonateTime = gpGlobals->curtime + timer;
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity )
|
||||
{
|
||||
//Assume all surfaces have the same elasticity
|
||||
float flSurfaceElasticity = 1.0;
|
||||
|
||||
//Don't bounce off of players with perfect elasticity
|
||||
if( trace.m_pEnt && trace.m_pEnt->IsPlayer() )
|
||||
{
|
||||
flSurfaceElasticity = 0.3;
|
||||
}
|
||||
|
||||
// if its breakable glass and we kill it, don't bounce.
|
||||
// give some damage to the glass, and if it breaks, pass
|
||||
// through it.
|
||||
bool breakthrough = false;
|
||||
|
||||
if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable" ) )
|
||||
{
|
||||
breakthrough = true;
|
||||
}
|
||||
|
||||
if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable_surf" ) )
|
||||
{
|
||||
breakthrough = true;
|
||||
}
|
||||
|
||||
if (breakthrough)
|
||||
{
|
||||
CTakeDamageInfo info( this, this, 10, DMG_CLUB );
|
||||
trace.m_pEnt->DispatchTraceAttack( info, GetAbsVelocity(), &trace );
|
||||
|
||||
ApplyMultiDamage();
|
||||
|
||||
if( trace.m_pEnt->m_iHealth <= 0 )
|
||||
{
|
||||
// slow our flight a little bit
|
||||
Vector vel = GetAbsVelocity();
|
||||
|
||||
vel *= 0.4;
|
||||
|
||||
SetAbsVelocity( vel );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float flTotalElasticity = GetElasticity() * flSurfaceElasticity;
|
||||
flTotalElasticity = clamp( flTotalElasticity, 0.0f, 0.9f );
|
||||
|
||||
// NOTE: A backoff of 2.0f is a reflection
|
||||
Vector vecAbsVelocity;
|
||||
PhysicsClipVelocity( GetAbsVelocity(), trace.plane.normal, vecAbsVelocity, 2.0f );
|
||||
vecAbsVelocity *= flTotalElasticity;
|
||||
|
||||
// Get the total velocity (player + conveyors, etc.)
|
||||
VectorAdd( vecAbsVelocity, GetBaseVelocity(), vecVelocity );
|
||||
float flSpeedSqr = DotProduct( vecVelocity, vecVelocity );
|
||||
|
||||
// Stop if on ground.
|
||||
if ( trace.plane.normal.z > 0.7f ) // Floor
|
||||
{
|
||||
// Verify that we have an entity.
|
||||
CBaseEntity *pEntity = trace.m_pEnt;
|
||||
Assert( pEntity );
|
||||
|
||||
SetAbsVelocity( vecAbsVelocity );
|
||||
|
||||
if ( flSpeedSqr < ( 30 * 30 ) )
|
||||
{
|
||||
if ( pEntity->IsStandable() )
|
||||
{
|
||||
SetGroundEntity( pEntity );
|
||||
}
|
||||
|
||||
// Reset velocities.
|
||||
SetAbsVelocity( vec3_origin );
|
||||
SetLocalAngularVelocity( vec3_angle );
|
||||
|
||||
//align to the ground so we're not standing on end
|
||||
QAngle angle;
|
||||
VectorAngles( trace.plane.normal, angle );
|
||||
|
||||
// rotate randomly in yaw
|
||||
angle[1] = random->RandomFloat( 0, 360 );
|
||||
|
||||
// TODO: rotate around trace.plane.normal
|
||||
|
||||
SetAbsAngles( angle );
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vecDelta = GetBaseVelocity() - vecAbsVelocity;
|
||||
Vector vecBaseDir = GetBaseVelocity();
|
||||
VectorNormalize( vecBaseDir );
|
||||
float flScale = vecDelta.Dot( vecBaseDir );
|
||||
|
||||
VectorScale( vecAbsVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, vecVelocity );
|
||||
VectorMA( vecVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, GetBaseVelocity() * flScale, vecVelocity );
|
||||
PhysicsPushEntity( vecVelocity, &trace );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we get *too* slow, we'll stick without ever coming to rest because
|
||||
// we'll get pushed down by gravity faster than we can escape from the wall.
|
||||
if ( flSpeedSqr < ( 30 * 30 ) )
|
||||
{
|
||||
// Reset velocities.
|
||||
SetAbsVelocity( vec3_origin );
|
||||
SetLocalAngularVelocity( vec3_angle );
|
||||
}
|
||||
else
|
||||
{
|
||||
SetAbsVelocity( vecAbsVelocity );
|
||||
}
|
||||
}
|
||||
|
||||
BounceSound();
|
||||
|
||||
// tell the bots a grenade has bounced
|
||||
CCSPlayer *player = ToCSPlayer(GetThrower());
|
||||
if ( player )
|
||||
{
|
||||
IGameEvent * event = gameeventmanager->CreateEvent( "grenade_bounce" );
|
||||
if ( event )
|
||||
{
|
||||
event->SetInt( "userid", player->GetUserID() );
|
||||
event->SetFloat( "x", GetAbsOrigin().x );
|
||||
event->SetFloat( "y", GetAbsOrigin().y );
|
||||
event->SetFloat( "z", GetAbsOrigin().z );
|
||||
gameeventmanager->FireEvent( event );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseCSGrenadeProjectile::SetupInitialTransmittedGrenadeVelocity( const Vector &velocity )
|
||||
{
|
||||
m_vInitialVelocity = velocity;
|
||||
}
|
||||
|
||||
#define MAX_WATER_SURFACE_DISTANCE 512
|
||||
|
||||
void CBaseCSGrenadeProjectile::Splash()
|
||||
{
|
||||
Vector centerPoint = GetAbsOrigin();
|
||||
Vector normal( 0, 0, 1 );
|
||||
|
||||
// Find our water surface by tracing up till we're out of the water
|
||||
trace_t tr;
|
||||
Vector vecTrace( 0, 0, MAX_WATER_SURFACE_DISTANCE );
|
||||
UTIL_TraceLine( centerPoint, centerPoint + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
|
||||
|
||||
// If we didn't start in water, we're above it
|
||||
if ( tr.startsolid == false )
|
||||
{
|
||||
// Look downward to find the surface
|
||||
vecTrace.Init( 0, 0, -MAX_WATER_SURFACE_DISTANCE );
|
||||
UTIL_TraceLine( centerPoint, centerPoint + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
|
||||
|
||||
// If we hit it, setup the explosion
|
||||
if ( tr.fraction < 1.0f )
|
||||
{
|
||||
centerPoint = tr.endpos;
|
||||
}
|
||||
else
|
||||
{
|
||||
//NOTENOTE: We somehow got into a splash without being near water?
|
||||
Assert( 0 );
|
||||
}
|
||||
}
|
||||
else if ( tr.fractionleftsolid )
|
||||
{
|
||||
// Otherwise we came out of the water at this point
|
||||
centerPoint = centerPoint + (vecTrace * tr.fractionleftsolid);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use default values, we're really deep
|
||||
}
|
||||
|
||||
CEffectData data;
|
||||
data.m_vOrigin = centerPoint;
|
||||
data.m_vNormal = normal;
|
||||
data.m_flScale = random->RandomFloat( 1.0f, 2.0f );
|
||||
|
||||
if ( GetWaterType() & CONTENTS_SLIME )
|
||||
{
|
||||
data.m_fFlags |= FX_WATER_IN_SLIME;
|
||||
}
|
||||
|
||||
DispatchEffect( "gunshotsplash", data );
|
||||
}
|
||||
|
||||
#endif // !CLIENT_DLL
|
||||
@@ -0,0 +1,88 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BASECSGRENADE_PROJECTILE_H
|
||||
#define BASECSGRENADE_PROJECTILE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "basegrenade_shared.h"
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CBaseCSGrenadeProjectile C_BaseCSGrenadeProjectile
|
||||
#else
|
||||
class CCSWeaponInfo;
|
||||
#endif
|
||||
|
||||
|
||||
class CBaseCSGrenadeProjectile : public CBaseGrenade
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CBaseCSGrenadeProjectile, CBaseGrenade );
|
||||
DECLARE_NETWORKCLASS();
|
||||
|
||||
virtual void Spawn();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// This gets sent to the client and placed in the client's interpolation history
|
||||
// so the projectile starts out moving right off the bat.
|
||||
CNetworkVector( m_vInitialVelocity );
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
CBaseCSGrenadeProjectile() {}
|
||||
CBaseCSGrenadeProjectile( const CBaseCSGrenadeProjectile& ) {}
|
||||
virtual int DrawModel( int flags );
|
||||
virtual void PostDataUpdate( DataUpdateType_t type );
|
||||
|
||||
float m_flSpawnTime;
|
||||
#else
|
||||
DECLARE_DATADESC();
|
||||
|
||||
virtual void PostConstructor( const char *className );
|
||||
virtual ~CBaseCSGrenadeProjectile();
|
||||
|
||||
//Constants for all CS Grenades
|
||||
static inline float GetGrenadeGravity() { return 0.4f; }
|
||||
static inline const float GetGrenadeFriction() { return 0.2f; }
|
||||
static inline const float GetGrenadeElasticity() { return 0.45f; }
|
||||
|
||||
//Think function to emit danger sounds for the AI
|
||||
void DangerSoundThink( void );
|
||||
|
||||
virtual float GetShakeAmplitude( void ) { return 0.0f; }
|
||||
virtual void Splash();
|
||||
|
||||
// Specify what velocity we want the grenade to have on the client immediately.
|
||||
// Without this, the entity wouldn't have an interpolation history initially, so it would
|
||||
// sit still until it had gotten a few updates from the server.
|
||||
void SetupInitialTransmittedGrenadeVelocity( const Vector &velocity );
|
||||
|
||||
// [jpaquin] give grenade projectiles a link back to the type
|
||||
// of weapon they are
|
||||
CCSWeaponInfo *m_pWeaponInfo;
|
||||
|
||||
protected:
|
||||
|
||||
//Set the time to detonate ( now + timer )
|
||||
void SetDetonateTimerLength( float timer );
|
||||
|
||||
private:
|
||||
|
||||
//Custom collision to allow for constant elasticity on hit surfaces
|
||||
virtual void ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity );
|
||||
|
||||
float m_flDetonateTime;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#endif // BASECSGRENADE_PROJECTILE_H
|
||||
@@ -0,0 +1,109 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Michael S. Booth (mike@turtlerockstudios.com), Leon Hartwig, 2003
|
||||
|
||||
#include "cbase.h"
|
||||
#include "basegrenade_shared.h"
|
||||
|
||||
#include "bot.h"
|
||||
#include "bot_util.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
/// @todo Remove this nasty hack - CreateFakeClient() calls CBot::Spawn, which needs the profile and team
|
||||
const BotProfile *g_botInitProfile = NULL;
|
||||
int g_botInitTeam = 0;
|
||||
|
||||
//
|
||||
// NOTE: Because CBot had to be templatized, the code was moved into bot.h
|
||||
//
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
ActiveGrenade::ActiveGrenade( CBaseGrenade *grenadeEntity )
|
||||
{
|
||||
m_entity = grenadeEntity;
|
||||
m_detonationPosition = grenadeEntity->GetAbsOrigin();
|
||||
m_dieTimestamp = 0.0f;
|
||||
m_radius = HEGrenadeRadius;
|
||||
|
||||
m_isSmoke = FStrEq( grenadeEntity->GetClassname(), "smokegrenade_projectile" );
|
||||
if ( m_isSmoke )
|
||||
{
|
||||
m_radius = SmokeGrenadeRadius;
|
||||
}
|
||||
|
||||
m_isFlashbang = FStrEq( grenadeEntity->GetClassname(), "flashbang_projectile" );
|
||||
if ( m_isFlashbang )
|
||||
{
|
||||
m_radius = FlashbangGrenadeRadius;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Called when the grenade in the world goes away
|
||||
*/
|
||||
void ActiveGrenade::OnEntityGone( void )
|
||||
{
|
||||
if (m_isSmoke)
|
||||
{
|
||||
// smoke lingers after grenade is gone
|
||||
const float smokeLingerTime = 4.0f;
|
||||
m_dieTimestamp = gpGlobals->curtime + smokeLingerTime;
|
||||
}
|
||||
|
||||
m_entity = NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
void ActiveGrenade::Update( void )
|
||||
{
|
||||
if (m_entity != NULL)
|
||||
{
|
||||
m_detonationPosition = m_entity->GetAbsOrigin();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if this grenade is valid
|
||||
*/
|
||||
bool ActiveGrenade::IsValid( void ) const
|
||||
{
|
||||
if ( m_isSmoke )
|
||||
{
|
||||
if ( m_entity == NULL && gpGlobals->curtime > m_dieTimestamp )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_entity == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
const Vector &ActiveGrenade::GetPosition( void ) const
|
||||
{
|
||||
// smoke grenades can vanish before the smoke itself does - refer to the detonation position
|
||||
if (m_entity == NULL)
|
||||
return GetDetonationPosition();
|
||||
|
||||
return m_entity->GetAbsOrigin();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Matthew D. Campbell (matt@turtlerockstudios.com), 2003
|
||||
|
||||
#ifndef BOT_CONSTANTS_H
|
||||
#define BOT_CONSTANTS_H
|
||||
|
||||
/// version number is MAJOR.MINOR
|
||||
#define BOT_VERSION_MAJOR 1
|
||||
#define BOT_VERSION_MINOR 50
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Difficulty levels
|
||||
*/
|
||||
enum BotDifficultyType
|
||||
{
|
||||
BOT_EASY = 0,
|
||||
BOT_NORMAL = 1,
|
||||
BOT_HARD = 2,
|
||||
BOT_EXPERT = 3,
|
||||
|
||||
NUM_DIFFICULTY_LEVELS
|
||||
};
|
||||
|
||||
#ifdef DEFINE_DIFFICULTY_NAMES
|
||||
const char *BotDifficultyName[] =
|
||||
{
|
||||
"EASY", "NORMAL", "HARD", "EXPERT", NULL
|
||||
};
|
||||
#else
|
||||
extern const char *BotDifficultyName[];
|
||||
#endif
|
||||
|
||||
#endif // BOT_CONSTANTS_H
|
||||
@@ -0,0 +1,490 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// bot_hide.cpp
|
||||
// Mechanisms for using Hiding Spots in the Navigation Mesh
|
||||
// Author: Michael Booth, 2003-2004
|
||||
|
||||
#include "cbase.h"
|
||||
#include "bot.h"
|
||||
#include "cs_nav_pathfind.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* If a player is at the given spot, return true
|
||||
*/
|
||||
bool IsSpotOccupied( CBaseEntity *me, const Vector &pos )
|
||||
{
|
||||
const float closeRange = 75.0f; // 50
|
||||
|
||||
// is there a player in this spot
|
||||
float range;
|
||||
CBasePlayer *player = UTIL_GetClosestPlayer( pos, &range );
|
||||
|
||||
if (player != me)
|
||||
{
|
||||
if (player && range < closeRange)
|
||||
return true;
|
||||
}
|
||||
|
||||
// is there is a hostage in this spot
|
||||
// BOTPORT: Implement hostage manager
|
||||
/*
|
||||
if (g_pHostages)
|
||||
{
|
||||
CHostage *hostage = g_pHostages->GetClosestHostage( *pos, &range );
|
||||
if (hostage && hostage != me && range < closeRange)
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
class CollectHidingSpotsFunctor
|
||||
{
|
||||
public:
|
||||
CollectHidingSpotsFunctor( CBaseEntity *me, const Vector &origin, float range, int flags, Place place = UNDEFINED_PLACE ) : m_origin( origin )
|
||||
{
|
||||
m_me = me;
|
||||
m_count = 0;
|
||||
m_range = range;
|
||||
m_flags = (unsigned char)flags;
|
||||
m_place = place;
|
||||
m_totalWeight = 0;
|
||||
}
|
||||
|
||||
enum { MAX_SPOTS = 256 };
|
||||
|
||||
bool operator() ( CNavArea *area )
|
||||
{
|
||||
// if a place is specified, only consider hiding spots from areas in that place
|
||||
if (m_place != UNDEFINED_PLACE && area->GetPlace() != m_place)
|
||||
return true;
|
||||
|
||||
// collect all the hiding spots in this area
|
||||
const HidingSpotVector *pSpots = area->GetHidingSpots();
|
||||
|
||||
FOR_EACH_VEC( (*pSpots), it )
|
||||
{
|
||||
const HidingSpot *spot = (*pSpots)[ it ];
|
||||
|
||||
// if we've filled up, stop searching
|
||||
if (m_count == MAX_SPOTS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure hiding spot is in range
|
||||
if (m_range > 0.0f)
|
||||
{
|
||||
if ((spot->GetPosition() - m_origin).IsLengthGreaterThan( m_range ))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// if a Player is using this hiding spot, don't consider it
|
||||
if (IsSpotOccupied( m_me, spot->GetPosition() ))
|
||||
{
|
||||
// player is in hiding spot
|
||||
/// @todo Check if player is moving or sitting still
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spot->GetArea() && (spot->GetArea()->GetAttributes() & NAV_MESH_DONT_HIDE))
|
||||
{
|
||||
// the area has been marked as DONT_HIDE since the last analysis, so let's ignore it
|
||||
continue;
|
||||
}
|
||||
|
||||
// only collect hiding spots with matching flags
|
||||
if (m_flags & spot->GetFlags())
|
||||
{
|
||||
m_hidingSpot[ m_count ] = &spot->GetPosition();
|
||||
m_hidingSpotWeight[ m_count ] = m_totalWeight;
|
||||
|
||||
// if it's an 'avoid' area, give it a low weight
|
||||
if ( spot->GetArea() && ( spot->GetArea()->GetAttributes() & NAV_MESH_AVOID ) )
|
||||
{
|
||||
m_totalWeight += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_totalWeight += 2;
|
||||
}
|
||||
|
||||
++m_count;
|
||||
}
|
||||
}
|
||||
|
||||
return (m_count < MAX_SPOTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the spot at index "i"
|
||||
*/
|
||||
void RemoveSpot( int i )
|
||||
{
|
||||
if (m_count == 0)
|
||||
return;
|
||||
|
||||
for( int j=i+1; j<m_count; ++j )
|
||||
m_hidingSpot[j-1] = m_hidingSpot[j];
|
||||
|
||||
--m_count;
|
||||
}
|
||||
|
||||
|
||||
int GetRandomHidingSpot( void )
|
||||
{
|
||||
int weight = RandomInt( 0, m_totalWeight-1 );
|
||||
for ( int i=0; i<m_count-1; ++i )
|
||||
{
|
||||
// if the next spot's starting weight is over the target weight, this spot is the one
|
||||
if ( m_hidingSpotWeight[i+1] >= weight )
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// if we didn't find any, it's the last one
|
||||
return m_count - 1;
|
||||
}
|
||||
|
||||
CBaseEntity *m_me;
|
||||
const Vector &m_origin;
|
||||
float m_range;
|
||||
|
||||
const Vector *m_hidingSpot[ MAX_SPOTS ];
|
||||
int m_hidingSpotWeight[ MAX_SPOTS ];
|
||||
int m_totalWeight;
|
||||
int m_count;
|
||||
|
||||
unsigned char m_flags;
|
||||
|
||||
Place m_place;
|
||||
};
|
||||
|
||||
/**
|
||||
* Do a breadth-first search to find a nearby hiding spot and return it.
|
||||
* Don't pick a hiding spot that a Player is currently occupying.
|
||||
* @todo Clean up this mess
|
||||
*/
|
||||
const Vector *FindNearbyHidingSpot( CBaseEntity *me, const Vector &pos, float maxRange, bool isSniper, bool useNearest )
|
||||
{
|
||||
CNavArea *startArea = TheNavMesh->GetNearestNavArea( pos );
|
||||
if (startArea == NULL)
|
||||
return NULL;
|
||||
|
||||
// collect set of nearby hiding spots
|
||||
if (isSniper)
|
||||
{
|
||||
CollectHidingSpotsFunctor collector( me, pos, maxRange, HidingSpot::IDEAL_SNIPER_SPOT );
|
||||
SearchSurroundingAreas( startArea, pos, collector, maxRange );
|
||||
|
||||
if (collector.m_count)
|
||||
{
|
||||
int which = collector.GetRandomHidingSpot();
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
else
|
||||
{
|
||||
// no ideal sniping spots, look for "good" sniping spots
|
||||
CollectHidingSpotsFunctor collector( me, pos, maxRange, HidingSpot::GOOD_SNIPER_SPOT );
|
||||
SearchSurroundingAreas( startArea, pos, collector, maxRange );
|
||||
|
||||
if (collector.m_count)
|
||||
{
|
||||
int which = collector.GetRandomHidingSpot();
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
|
||||
// no sniping spots at all.. fall through and pick a normal hiding spot
|
||||
}
|
||||
}
|
||||
|
||||
// collect hiding spots with decent "cover"
|
||||
CollectHidingSpotsFunctor collector( me, pos, maxRange, HidingSpot::IN_COVER );
|
||||
SearchSurroundingAreas( startArea, pos, collector, maxRange );
|
||||
|
||||
if (collector.m_count == 0)
|
||||
{
|
||||
// no hiding spots at all - if we're not a sniper, try to find a sniper spot to use instead
|
||||
if (!isSniper)
|
||||
{
|
||||
return FindNearbyHidingSpot( me, pos, maxRange, true, useNearest );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (useNearest)
|
||||
{
|
||||
// return closest hiding spot
|
||||
const Vector *closest = NULL;
|
||||
float closeRangeSq = 9999999999.9f;
|
||||
for( int i=0; i<collector.m_count; ++i )
|
||||
{
|
||||
float rangeSq = (*collector.m_hidingSpot[i] - pos).LengthSqr();
|
||||
if (rangeSq < closeRangeSq)
|
||||
{
|
||||
closeRangeSq = rangeSq;
|
||||
closest = collector.m_hidingSpot[i];
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
// select a hiding spot at random
|
||||
int which = collector.GetRandomHidingSpot();
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Select a random hiding spot among the nav areas that are tagged with the given place
|
||||
*/
|
||||
const Vector *FindRandomHidingSpot( CBaseEntity *me, Place place, bool isSniper )
|
||||
{
|
||||
// collect set of nearby hiding spots
|
||||
if (isSniper)
|
||||
{
|
||||
CollectHidingSpotsFunctor collector( me, me->GetAbsOrigin(), -1.0f, HidingSpot::IDEAL_SNIPER_SPOT, place );
|
||||
TheNavMesh->ForAllAreas( collector );
|
||||
|
||||
if (collector.m_count)
|
||||
{
|
||||
int which = RandomInt( 0, collector.m_count-1 );
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
else
|
||||
{
|
||||
// no ideal sniping spots, look for "good" sniping spots
|
||||
CollectHidingSpotsFunctor collector( me, me->GetAbsOrigin(), -1.0f, HidingSpot::GOOD_SNIPER_SPOT, place );
|
||||
TheNavMesh->ForAllAreas( collector );
|
||||
|
||||
if (collector.m_count)
|
||||
{
|
||||
int which = RandomInt( 0, collector.m_count-1 );
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
|
||||
// no sniping spots at all.. fall through and pick a normal hiding spot
|
||||
}
|
||||
}
|
||||
|
||||
// collect hiding spots with decent "cover"
|
||||
CollectHidingSpotsFunctor collector( me, me->GetAbsOrigin(), -1.0f, HidingSpot::IN_COVER, place );
|
||||
TheNavMesh->ForAllAreas( collector );
|
||||
|
||||
if (collector.m_count == 0)
|
||||
return NULL;
|
||||
|
||||
// select a hiding spot at random
|
||||
int which = RandomInt( 0, collector.m_count-1 );
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Select a nearby retreat spot.
|
||||
* Don't pick a hiding spot that a Player is currently occupying.
|
||||
* If "avoidTeam" is nonzero, avoid getting close to members of that team.
|
||||
*/
|
||||
const Vector *FindNearbyRetreatSpot( CBaseEntity *me, const Vector &start, float maxRange, int avoidTeam )
|
||||
{
|
||||
CNavArea *startArea = TheNavMesh->GetNearestNavArea( start );
|
||||
if (startArea == NULL)
|
||||
return NULL;
|
||||
|
||||
// collect hiding spots with decent "cover"
|
||||
CollectHidingSpotsFunctor collector( me, start, maxRange, HidingSpot::IN_COVER );
|
||||
SearchSurroundingAreas( startArea, start, collector, maxRange );
|
||||
|
||||
if (collector.m_count == 0)
|
||||
return NULL;
|
||||
|
||||
// find the closest unoccupied hiding spot that crosses the least lines of fire and has the best cover
|
||||
for( int i=0; i<collector.m_count; ++i )
|
||||
{
|
||||
// check if we would have to cross a line of fire to reach this hiding spot
|
||||
if (IsCrossingLineOfFire( start, *collector.m_hidingSpot[i], me ))
|
||||
{
|
||||
collector.RemoveSpot( i );
|
||||
|
||||
// back up a step, so iteration won't skip a spot
|
||||
--i;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if there is someone on the avoidTeam near this hiding spot
|
||||
if (avoidTeam)
|
||||
{
|
||||
float range;
|
||||
if (UTIL_GetClosestPlayer( *collector.m_hidingSpot[i], avoidTeam, &range ))
|
||||
{
|
||||
const float dangerRange = 150.0f;
|
||||
if (range < dangerRange)
|
||||
{
|
||||
// there is an avoidable player too near this spot - remove it
|
||||
collector.RemoveSpot( i );
|
||||
|
||||
// back up a step, so iteration won't skip a spot
|
||||
--i;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (collector.m_count <= 0)
|
||||
return NULL;
|
||||
|
||||
// all remaining spots are ok - pick one at random
|
||||
int which = RandomInt( 0, collector.m_count-1 );
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Functor to collect all hiding spots in range that we can reach before the enemy arrives.
|
||||
* NOTE: This only works for the initial rush.
|
||||
*/
|
||||
class CollectArriveFirstSpotsFunctor
|
||||
{
|
||||
public:
|
||||
CollectArriveFirstSpotsFunctor( CBaseEntity *me, const Vector &searchOrigin, float enemyArriveTime, float range, int flags ) : m_searchOrigin( searchOrigin )
|
||||
{
|
||||
m_me = me;
|
||||
m_count = 0;
|
||||
m_range = range;
|
||||
m_flags = (unsigned char)flags;
|
||||
m_enemyArriveTime = enemyArriveTime;
|
||||
}
|
||||
|
||||
enum { MAX_SPOTS = 256 };
|
||||
|
||||
bool operator() ( CNavArea *area )
|
||||
{
|
||||
// collect all the hiding spots in this area
|
||||
const HidingSpotVector *pSpots = area->GetHidingSpots();
|
||||
|
||||
FOR_EACH_VEC( (*pSpots), it )
|
||||
{
|
||||
const HidingSpot *spot = (*pSpots)[ it ];
|
||||
|
||||
// make sure hiding spot is in range
|
||||
if (m_range > 0.0f)
|
||||
{
|
||||
if ((spot->GetPosition() - m_searchOrigin).IsLengthGreaterThan( m_range ))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// if a Player is using this hiding spot, don't consider it
|
||||
if (IsSpotOccupied( m_me, spot->GetPosition() ))
|
||||
{
|
||||
// player is in hiding spot
|
||||
/// @todo Check if player is moving or sitting still
|
||||
continue;
|
||||
}
|
||||
|
||||
// only collect hiding spots with matching flags
|
||||
if (!(m_flags & spot->GetFlags()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// only collect this hiding spot if we can reach it before the enemy arrives
|
||||
// NOTE: This assumes the area is fairly small and the difference of moving to the corner vs the center is small
|
||||
const float settleTime = 1.0f;
|
||||
if (spot->GetArea()->GetEarliestOccupyTime( m_me->GetTeamNumber() ) + settleTime < m_enemyArriveTime)
|
||||
{
|
||||
m_hidingSpot[ m_count++ ] = spot;
|
||||
}
|
||||
}
|
||||
|
||||
// if we've filled up, stop searching
|
||||
if (m_count == MAX_SPOTS)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CBaseEntity *m_me;
|
||||
const Vector &m_searchOrigin;
|
||||
|
||||
float m_range;
|
||||
float m_enemyArriveTime;
|
||||
unsigned char m_flags;
|
||||
|
||||
const HidingSpot *m_hidingSpot[ MAX_SPOTS ];
|
||||
int m_count;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Select a hiding spot that we can reach before the enemy arrives.
|
||||
* NOTE: This only works for the initial rush.
|
||||
*/
|
||||
const HidingSpot *FindInitialEncounterSpot( CBaseEntity *me, const Vector &searchOrigin, float enemyArriveTime, float maxRange, bool isSniper )
|
||||
{
|
||||
CNavArea *startArea = TheNavMesh->GetNearestNavArea( searchOrigin );
|
||||
if (startArea == NULL)
|
||||
return NULL;
|
||||
|
||||
// collect set of nearby hiding spots
|
||||
if (isSniper)
|
||||
{
|
||||
CollectArriveFirstSpotsFunctor collector( me, searchOrigin, enemyArriveTime, maxRange, HidingSpot::IDEAL_SNIPER_SPOT );
|
||||
SearchSurroundingAreas( startArea, searchOrigin, collector, maxRange );
|
||||
|
||||
if (collector.m_count)
|
||||
{
|
||||
int which = RandomInt( 0, collector.m_count-1 );
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
else
|
||||
{
|
||||
// no ideal sniping spots, look for "good" sniping spots
|
||||
CollectArriveFirstSpotsFunctor collector( me, searchOrigin, enemyArriveTime, maxRange, HidingSpot::GOOD_SNIPER_SPOT );
|
||||
SearchSurroundingAreas( startArea, searchOrigin, collector, maxRange );
|
||||
|
||||
if (collector.m_count)
|
||||
{
|
||||
int which = RandomInt( 0, collector.m_count-1 );
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
|
||||
// no sniping spots at all.. fall through and pick a normal hiding spot
|
||||
}
|
||||
}
|
||||
|
||||
// collect hiding spots with decent "cover"
|
||||
CollectArriveFirstSpotsFunctor collector( me, searchOrigin, enemyArriveTime, maxRange, HidingSpot::IN_COVER | HidingSpot::EXPOSED );
|
||||
SearchSurroundingAreas( startArea, searchOrigin, collector, maxRange );
|
||||
|
||||
if (collector.m_count == 0)
|
||||
return NULL;
|
||||
|
||||
// select a hiding spot at random
|
||||
int which = RandomInt( 0, collector.m_count-1 );
|
||||
return collector.m_hidingSpot[ which ];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,402 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Michael S. Booth (mike@turtlerockstudios.com), 2003
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "bot.h"
|
||||
#include "bot_manager.h"
|
||||
#include "nav_area.h"
|
||||
#include "bot_util.h"
|
||||
#include "basegrenade_shared.h"
|
||||
|
||||
#include "cs_bot.h"
|
||||
|
||||
#include "tier0/vprof.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
float g_BotUpkeepInterval = 0.0f;
|
||||
float g_BotUpdateInterval = 0.0f;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
CBotManager::CBotManager()
|
||||
{
|
||||
InitBotTrig();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
CBotManager::~CBotManager()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Invoked when the round is restarting
|
||||
*/
|
||||
void CBotManager::RestartRound( void )
|
||||
{
|
||||
DestroyAllGrenades();
|
||||
ClearDebugMessages();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Invoked at the start of each frame
|
||||
*/
|
||||
void CBotManager::StartFrame( void )
|
||||
{
|
||||
VPROF_BUDGET( "CBotManager::StartFrame", VPROF_BUDGETGROUP_NPCS );
|
||||
|
||||
ValidateActiveGrenades();
|
||||
|
||||
// debug smoke grenade visualization
|
||||
if (cv_bot_debug.GetInt() == 5)
|
||||
{
|
||||
Vector edge, lastEdge;
|
||||
|
||||
FOR_EACH_LL( m_activeGrenadeList, it )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[ it ];
|
||||
|
||||
const Vector &pos = ag->GetDetonationPosition();
|
||||
|
||||
UTIL_DrawBeamPoints( pos, pos + Vector( 0, 0, 50 ), 1, 255, 100, 0 );
|
||||
|
||||
lastEdge = Vector( ag->GetRadius() + pos.x, pos.y, pos.z );
|
||||
float angle;
|
||||
for( angle=0.0f; angle <= 180.0f; angle += 22.5f )
|
||||
{
|
||||
edge.x = ag->GetRadius() * BotCOS( angle ) + pos.x;
|
||||
edge.y = pos.y;
|
||||
edge.z = ag->GetRadius() * BotSIN( angle ) + pos.z;
|
||||
|
||||
UTIL_DrawBeamPoints( edge, lastEdge, 1, 255, 50, 0 );
|
||||
|
||||
lastEdge = edge;
|
||||
}
|
||||
|
||||
lastEdge = Vector( pos.x, ag->GetRadius() + pos.y, pos.z );
|
||||
for( angle=0.0f; angle <= 180.0f; angle += 22.5f )
|
||||
{
|
||||
edge.x = pos.x;
|
||||
edge.y = ag->GetRadius() * BotCOS( angle ) + pos.y;
|
||||
edge.z = ag->GetRadius() * BotSIN( angle ) + pos.z;
|
||||
|
||||
UTIL_DrawBeamPoints( edge, lastEdge, 1, 255, 50, 0 );
|
||||
|
||||
lastEdge = edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set frame duration
|
||||
g_BotUpkeepInterval = m_frameTimer.GetElapsedTime();
|
||||
m_frameTimer.Start();
|
||||
|
||||
g_BotUpdateInterval = (g_BotUpdateSkipCount+1) * g_BotUpkeepInterval;
|
||||
|
||||
//
|
||||
// Process each active bot
|
||||
//
|
||||
for( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (!player)
|
||||
continue;
|
||||
|
||||
// Hack for now so the temp bot code works. The temp bots are very useful for debugging
|
||||
// because they can be setup to mimic the player's usercmds.
|
||||
if (player->IsBot() && IsEntityValid( player ) )
|
||||
{
|
||||
// EVIL: Messes up vtables
|
||||
//CBot< CBasePlayer > *bot = static_cast< CBot< CBasePlayer > * >( player );
|
||||
CCSBot *bot = dynamic_cast< CCSBot * >( player );
|
||||
|
||||
if ( bot )
|
||||
{
|
||||
bot->Upkeep();
|
||||
|
||||
if (((gpGlobals->tickcount + bot->entindex()) % g_BotUpdateSkipCount) == 0)
|
||||
{
|
||||
bot->ResetCommand();
|
||||
bot->Update();
|
||||
}
|
||||
|
||||
bot->UpdatePlayer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Add an active grenade to the bot's awareness
|
||||
*/
|
||||
void CBotManager::AddGrenade( CBaseGrenade *grenade )
|
||||
{
|
||||
ActiveGrenade *ag = new ActiveGrenade( grenade );
|
||||
m_activeGrenadeList.AddToTail( ag );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* The grenade entity in the world is going away
|
||||
*/
|
||||
void CBotManager::RemoveGrenade( CBaseGrenade *grenade )
|
||||
{
|
||||
FOR_EACH_LL( m_activeGrenadeList, it )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[ it ];
|
||||
|
||||
if (ag->IsEntity( grenade ))
|
||||
{
|
||||
ag->OnEntityGone();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* The grenade entity has changed its radius
|
||||
*/
|
||||
void CBotManager::SetGrenadeRadius( CBaseGrenade *grenade, float radius )
|
||||
{
|
||||
FOR_EACH_LL( m_activeGrenadeList, it )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[ it ];
|
||||
|
||||
if (ag->IsEntity( grenade ))
|
||||
{
|
||||
ag->SetRadius( radius );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Destroy any invalid active grenades
|
||||
*/
|
||||
void CBotManager::ValidateActiveGrenades( void )
|
||||
{
|
||||
int it = m_activeGrenadeList.Head();
|
||||
|
||||
while( it != m_activeGrenadeList.InvalidIndex() )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[ it ];
|
||||
|
||||
int current = it;
|
||||
it = m_activeGrenadeList.Next( it );
|
||||
|
||||
// lazy validation
|
||||
if (!ag->IsValid())
|
||||
{
|
||||
m_activeGrenadeList.Remove( current );
|
||||
delete ag;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ag->Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
void CBotManager::DestroyAllGrenades( void )
|
||||
{
|
||||
m_activeGrenadeList.PurgeAndDeleteElements();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if position is inside a smoke cloud
|
||||
*/
|
||||
bool CBotManager::IsInsideSmokeCloud( const Vector *pos )
|
||||
{
|
||||
int it = m_activeGrenadeList.Head();
|
||||
|
||||
while( it != m_activeGrenadeList.InvalidIndex() )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[ it ];
|
||||
|
||||
int current = it;
|
||||
it = m_activeGrenadeList.Next( it );
|
||||
|
||||
// lazy validation
|
||||
if (!ag->IsValid())
|
||||
{
|
||||
m_activeGrenadeList.Remove( current );
|
||||
delete ag;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ag->IsSmoke())
|
||||
{
|
||||
const Vector &smokeOrigin = ag->GetDetonationPosition();
|
||||
|
||||
if ((smokeOrigin - *pos).IsLengthLessThan( ag->GetRadius() ))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if line intersects smoke volume
|
||||
* Determine the length of the line of sight covered by each smoke cloud,
|
||||
* and sum them (overlap is additive for obstruction).
|
||||
* If the overlap exceeds the threshold, the bot can't see through.
|
||||
*/
|
||||
bool CBotManager::IsLineBlockedBySmoke( const Vector &from, const Vector &to, float grenadeBloat )
|
||||
{
|
||||
VPROF_BUDGET( "CBotManager::IsLineBlockedBySmoke", VPROF_BUDGETGROUP_NPCS );
|
||||
|
||||
float totalSmokedLength = 0.0f; // distance along line of sight covered by smoke
|
||||
|
||||
// compute unit vector and length of line of sight segment
|
||||
Vector sightDir = to - from;
|
||||
float sightLength = sightDir.NormalizeInPlace();
|
||||
|
||||
FOR_EACH_LL( m_activeGrenadeList, it )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[ it ];
|
||||
const float smokeRadiusSq = ag->GetRadius() * ag->GetRadius() * grenadeBloat * grenadeBloat;
|
||||
|
||||
if (ag->IsSmoke())
|
||||
{
|
||||
const Vector &smokeOrigin = ag->GetDetonationPosition();
|
||||
|
||||
Vector toGrenade = smokeOrigin - from;
|
||||
|
||||
float alongDist = DotProduct( toGrenade, sightDir );
|
||||
|
||||
// compute closest point to grenade along line of sight ray
|
||||
Vector close;
|
||||
|
||||
// constrain closest point to line segment
|
||||
if (alongDist < 0.0f)
|
||||
close = from;
|
||||
else if (alongDist >= sightLength)
|
||||
close = to;
|
||||
else
|
||||
close = from + sightDir * alongDist;
|
||||
|
||||
// if closest point is within smoke radius, the line overlaps the smoke cloud
|
||||
Vector toClose = close - smokeOrigin;
|
||||
float lengthSq = toClose.LengthSqr();
|
||||
|
||||
if (lengthSq < smokeRadiusSq)
|
||||
{
|
||||
// some portion of the ray intersects the cloud
|
||||
|
||||
float fromSq = toGrenade.LengthSqr();
|
||||
float toSq = (smokeOrigin - to).LengthSqr();
|
||||
|
||||
if (fromSq < smokeRadiusSq)
|
||||
{
|
||||
if (toSq < smokeRadiusSq)
|
||||
{
|
||||
// both 'from' and 'to' lie within the cloud
|
||||
// entire length is smoked
|
||||
totalSmokedLength += (to - from).Length();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 'from' is inside the cloud, 'to' is outside
|
||||
// compute half of total smoked length as if ray crosses entire cloud chord
|
||||
float halfSmokedLength = (float)sqrt( smokeRadiusSq - lengthSq );
|
||||
|
||||
if (alongDist > 0.0f)
|
||||
{
|
||||
// ray goes thru 'close'
|
||||
totalSmokedLength += halfSmokedLength + (close - from).Length();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ray starts after 'close'
|
||||
totalSmokedLength += halfSmokedLength - (close - from).Length();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (toSq < smokeRadiusSq)
|
||||
{
|
||||
// 'from' is outside the cloud, 'to' is inside
|
||||
// compute half of total smoked length as if ray crosses entire cloud chord
|
||||
float halfSmokedLength = (float)sqrt( smokeRadiusSq - lengthSq );
|
||||
|
||||
Vector v = to - smokeOrigin;
|
||||
if (DotProduct( v, sightDir ) > 0.0f)
|
||||
{
|
||||
// ray goes thru 'close'
|
||||
totalSmokedLength += halfSmokedLength + (close - to).Length();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ray ends before 'close'
|
||||
totalSmokedLength += halfSmokedLength - (close - to).Length();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 'from' and 'to' lie outside of the cloud - the line of sight completely crosses it
|
||||
// determine the length of the chord that crosses the cloud
|
||||
float smokedLength = 2.0f * (float)sqrt( smokeRadiusSq - lengthSq );
|
||||
|
||||
totalSmokedLength += smokedLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// define how much smoke a bot can see thru
|
||||
const float maxSmokedLength = 0.7f * SmokeGrenadeRadius;
|
||||
|
||||
// return true if the total length of smoke-covered line-of-sight is too much
|
||||
return (totalSmokedLength > maxSmokedLength);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
void CBotManager::ClearDebugMessages( void )
|
||||
{
|
||||
m_debugMessageCount = 0;
|
||||
m_currentDebugMessage = -1;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Add a new debug message to the message history
|
||||
*/
|
||||
void CBotManager::AddDebugMessage( const char *msg )
|
||||
{
|
||||
if (++m_currentDebugMessage >= MAX_DBG_MSGS)
|
||||
{
|
||||
m_currentDebugMessage = 0;
|
||||
}
|
||||
|
||||
if (m_debugMessageCount < MAX_DBG_MSGS)
|
||||
{
|
||||
++m_debugMessageCount;
|
||||
}
|
||||
|
||||
Q_strncpy( m_debugMessage[ m_currentDebugMessage ].m_string, msg, MAX_DBG_MSG_SIZE );
|
||||
m_debugMessage[ m_currentDebugMessage ].m_age.Start();
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Michael S. Booth (mike@turtlerockstudios.com), 2003
|
||||
|
||||
#ifndef BASE_CONTROL_H
|
||||
#define BASE_CONTROL_H
|
||||
|
||||
#pragma warning( disable : 4530 ) // STL uses exceptions, but we are not compiling with them - ignore warning
|
||||
|
||||
extern float g_BotUpkeepInterval; ///< duration between bot upkeeps
|
||||
extern float g_BotUpdateInterval; ///< duration between bot updates
|
||||
const int g_BotUpdateSkipCount = 2; ///< number of upkeep periods to skip update
|
||||
|
||||
class CNavArea;
|
||||
|
||||
/// TODO: move CS-specific defines into CSBot files
|
||||
enum
|
||||
{
|
||||
SmokeGrenadeRadius = 155,
|
||||
FlashbangGrenadeRadius = 115,
|
||||
HEGrenadeRadius = 115,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
class CBaseGrenade;
|
||||
|
||||
/**
|
||||
* An ActiveGrenade is a representation of a grenade in the world
|
||||
* NOTE: Currently only used for smoke grenade line-of-sight testing
|
||||
* @todo Use system allow bots to avoid HE and Flashbangs
|
||||
*/
|
||||
class ActiveGrenade
|
||||
{
|
||||
public:
|
||||
ActiveGrenade( CBaseGrenade *grenadeEntity );
|
||||
|
||||
void OnEntityGone( void ); ///< called when the grenade in the world goes away
|
||||
void Update( void ); ///< called every frame
|
||||
bool IsValid( void ) const ; ///< return true if this grenade is valid
|
||||
|
||||
bool IsEntity( CBaseGrenade *grenade ) const { return (grenade == m_entity) ? true : false; }
|
||||
CBaseGrenade *GetEntity( void ) const { return m_entity; }
|
||||
|
||||
const Vector &GetDetonationPosition( void ) const { return m_detonationPosition; }
|
||||
const Vector &GetPosition( void ) const;
|
||||
bool IsSmoke( void ) const { return m_isSmoke; }
|
||||
bool IsFlashbang( void ) const { return m_isFlashbang; }
|
||||
CBaseGrenade *GetGrenade( void ) { return m_entity; }
|
||||
float GetRadius( void ) const { return m_radius; }
|
||||
void SetRadius( float radius ) { m_radius = radius; }
|
||||
|
||||
private:
|
||||
CBaseGrenade *m_entity; ///< the entity
|
||||
Vector m_detonationPosition; ///< the location where the grenade detonated (smoke)
|
||||
float m_dieTimestamp; ///< time this should go away after m_entity is NULL
|
||||
bool m_isSmoke; ///< true if this is a smoke grenade
|
||||
bool m_isFlashbang; ///< true if this is a flashbang grenade
|
||||
float m_radius;
|
||||
};
|
||||
|
||||
typedef CUtlLinkedList<ActiveGrenade *> ActiveGrenadeList;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* This class manages all active bots, propagating events to them and updating them.
|
||||
*/
|
||||
class CBotManager
|
||||
{
|
||||
public:
|
||||
CBotManager();
|
||||
virtual ~CBotManager();
|
||||
|
||||
CBasePlayer *AllocateAndBindBotEntity( edict_t *ed ); ///< allocate the appropriate entity for the bot and bind it to the given edict
|
||||
virtual CBasePlayer *AllocateBotEntity( void ) = 0; ///< factory method to allocate the appropriate entity for the bot
|
||||
|
||||
virtual void ClientDisconnect( CBaseEntity *entity ) = 0;
|
||||
virtual bool ClientCommand( CBasePlayer *player, const CCommand &args ) = 0;
|
||||
|
||||
virtual void ServerActivate( void ) = 0;
|
||||
virtual void ServerDeactivate( void ) = 0;
|
||||
virtual bool ServerCommand( const char * pcmd ) = 0;
|
||||
|
||||
virtual void RestartRound( void ); ///< (EXTEND) invoked when a new round begins
|
||||
virtual void StartFrame( void ); ///< (EXTEND) called each frame
|
||||
|
||||
virtual unsigned int GetPlayerPriority( CBasePlayer *player ) const = 0; ///< return priority of player (0 = max pri)
|
||||
|
||||
|
||||
void AddGrenade( CBaseGrenade *grenade ); ///< add an active grenade to the bot's awareness
|
||||
void RemoveGrenade( CBaseGrenade *grenade ); ///< the grenade entity in the world is going away
|
||||
void SetGrenadeRadius( CBaseGrenade *grenade, float radius ); ///< the radius of the grenade entity (or associated smoke cloud)
|
||||
void ValidateActiveGrenades( void ); ///< destroy any invalid active grenades
|
||||
void DestroyAllGrenades( void );
|
||||
bool IsLineBlockedBySmoke( const Vector &from, const Vector &to, float grenadeBloat = 1.0f ); ///< return true if line intersects smoke volume, with grenade radius increased by the grenadeBloat factor
|
||||
bool IsInsideSmokeCloud( const Vector *pos ); ///< return true if position is inside a smoke cloud
|
||||
|
||||
//
|
||||
// Invoke functor on all active grenades.
|
||||
// If any functor call return false, return false. Otherwise, return true.
|
||||
//
|
||||
template < typename T >
|
||||
bool ForEachGrenade( T &func )
|
||||
{
|
||||
int it = m_activeGrenadeList.Head();
|
||||
|
||||
while( it != m_activeGrenadeList.InvalidIndex() )
|
||||
{
|
||||
ActiveGrenade *ag = m_activeGrenadeList[ it ];
|
||||
|
||||
int current = it;
|
||||
it = m_activeGrenadeList.Next( it );
|
||||
|
||||
// lazy validation
|
||||
if (!ag->IsValid())
|
||||
{
|
||||
m_activeGrenadeList.Remove( current );
|
||||
delete ag;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (func( ag ) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
enum { MAX_DBG_MSG_SIZE = 1024 };
|
||||
struct DebugMessage
|
||||
{
|
||||
char m_string[ MAX_DBG_MSG_SIZE ];
|
||||
IntervalTimer m_age;
|
||||
};
|
||||
|
||||
// debug message history -------------------------------------------------------------------------------
|
||||
int GetDebugMessageCount( void ) const; ///< get number of debug messages in history
|
||||
const DebugMessage *GetDebugMessage( int which = 0 ) const; ///< return the debug message emitted by the bot (0 = most recent)
|
||||
void ClearDebugMessages( void );
|
||||
void AddDebugMessage( const char *msg );
|
||||
|
||||
|
||||
private:
|
||||
ActiveGrenadeList m_activeGrenadeList;///< the list of active grenades the bots are aware of
|
||||
|
||||
enum { MAX_DBG_MSGS = 6 };
|
||||
DebugMessage m_debugMessage[ MAX_DBG_MSGS ]; ///< debug message history
|
||||
int m_debugMessageCount;
|
||||
int m_currentDebugMessage;
|
||||
|
||||
IntervalTimer m_frameTimer; ///< for measuring each frame's duration
|
||||
};
|
||||
|
||||
|
||||
inline CBasePlayer *CBotManager::AllocateAndBindBotEntity( edict_t *ed )
|
||||
{
|
||||
CBasePlayer::s_PlayerEdict = ed;
|
||||
return AllocateBotEntity();
|
||||
}
|
||||
|
||||
inline int CBotManager::GetDebugMessageCount( void ) const
|
||||
{
|
||||
return m_debugMessageCount;
|
||||
}
|
||||
|
||||
inline const CBotManager::DebugMessage *CBotManager::GetDebugMessage( int which ) const
|
||||
{
|
||||
if (which >= m_debugMessageCount)
|
||||
return NULL;
|
||||
|
||||
int i = m_currentDebugMessage - which;
|
||||
if (i < 0)
|
||||
i += MAX_DBG_MSGS;
|
||||
|
||||
return &m_debugMessage[ i ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// global singleton to create and control bots
|
||||
extern CBotManager *TheBots;
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,704 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Michael S. Booth (mike@turtlerockstudios.com), 2003
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#pragma warning( disable : 4530 ) // STL uses exceptions, but we are not compiling with them - ignore warning
|
||||
|
||||
#define DEFINE_DIFFICULTY_NAMES
|
||||
#include "bot_profile.h"
|
||||
#include "shared_util.h"
|
||||
|
||||
#include "bot.h"
|
||||
#include "bot_util.h"
|
||||
#include "cs_bot.h" // BOTPORT: Remove this CS dependency
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
BotProfileManager *TheBotProfiles = NULL;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Generates a filename-decorated skin name
|
||||
*/
|
||||
static const char * GetDecoratedSkinName( const char *name, const char *filename )
|
||||
{
|
||||
const int BufLen = _MAX_PATH + 64;
|
||||
static char buf[BufLen];
|
||||
Q_snprintf( buf, sizeof( buf ), "%s/%s", filename, name );
|
||||
return buf;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
const char* BotProfile::GetWeaponPreferenceAsString( int i ) const
|
||||
{
|
||||
if ( i < 0 || i >= m_weaponPreferenceCount )
|
||||
return NULL;
|
||||
|
||||
return WeaponIDToAlias( m_weaponPreference[ i ] );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if this profile has a primary weapon preference
|
||||
*/
|
||||
bool BotProfile::HasPrimaryPreference( void ) const
|
||||
{
|
||||
for( int i=0; i<m_weaponPreferenceCount; ++i )
|
||||
{
|
||||
if (IsPrimaryWeapon( m_weaponPreference[i] ))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if this profile has a pistol weapon preference
|
||||
*/
|
||||
bool BotProfile::HasPistolPreference( void ) const
|
||||
{
|
||||
for( int i=0; i<m_weaponPreferenceCount; ++i )
|
||||
if (IsSecondaryWeapon( m_weaponPreference[i] ))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if this profile is valid for the specified team
|
||||
*/
|
||||
bool BotProfile::IsValidForTeam( int team ) const
|
||||
{
|
||||
return ( team == TEAM_UNASSIGNED || m_teams == TEAM_UNASSIGNED || team == m_teams );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if this profile inherits from the specified template
|
||||
*/
|
||||
bool BotProfile::InheritsFrom( const char *name ) const
|
||||
{
|
||||
if ( WildcardMatch( name, GetName() ) )
|
||||
return true;
|
||||
|
||||
for ( int i=0; i<m_templates.Count(); ++i )
|
||||
{
|
||||
const BotProfile *queryTemplate = m_templates[i];
|
||||
if ( queryTemplate->InheritsFrom( name ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
BotProfileManager::BotProfileManager( void )
|
||||
{
|
||||
m_nextSkin = 0;
|
||||
for (int i=0; i<NumCustomSkins; ++i)
|
||||
{
|
||||
m_skins[i] = NULL;
|
||||
m_skinFilenames[i] = NULL;
|
||||
m_skinModelnames[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Load the bot profile database
|
||||
*/
|
||||
void BotProfileManager::Init( const char *filename, unsigned int *checksum )
|
||||
{
|
||||
FileHandle_t file = filesystem->Open( filename, "r" );
|
||||
|
||||
if (!file)
|
||||
{
|
||||
if ( true ) // UTIL_IsGame( "czero" ) )
|
||||
{
|
||||
CONSOLE_ECHO( "WARNING: Cannot access bot profile database '%s'\n", filename );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int dataLength = filesystem->Size( filename );
|
||||
char *dataPointer = new char[ dataLength ];
|
||||
int dataReadLength = filesystem->Read( dataPointer, dataLength, file );
|
||||
filesystem->Close( file );
|
||||
if ( dataReadLength > 0 )
|
||||
{
|
||||
// NULL-terminate based on the length read in, since Read() can transform \r\n to \n and
|
||||
// return fewer bytes than we were expecting.
|
||||
dataPointer[ dataReadLength - 1 ] = 0;
|
||||
}
|
||||
|
||||
const char *dataFile = dataPointer;
|
||||
|
||||
// compute simple checksum
|
||||
if (checksum)
|
||||
{
|
||||
*checksum = 0; // ComputeSimpleChecksum( (const unsigned char *)dataPointer, dataLength );
|
||||
}
|
||||
|
||||
BotProfile defaultProfile;
|
||||
|
||||
//
|
||||
// Parse the BotProfile.db into BotProfile instances
|
||||
//
|
||||
while( true )
|
||||
{
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
break;
|
||||
|
||||
char *token = SharedGetToken();
|
||||
|
||||
bool isDefault = (!stricmp( token, "Default" ));
|
||||
bool isTemplate = (!stricmp( token, "Template" ));
|
||||
bool isCustomSkin = (!stricmp( token, "Skin" ));
|
||||
|
||||
if ( isCustomSkin )
|
||||
{
|
||||
const int BufLen = 64;
|
||||
char skinName[BufLen];
|
||||
|
||||
// get skin name
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected skin name\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
token = SharedGetToken();
|
||||
Q_snprintf( skinName, sizeof( skinName ), "%s", token );
|
||||
|
||||
// get attribute name
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected 'Model'\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
token = SharedGetToken();
|
||||
if (stricmp( "Model", token ))
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected 'Model'\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
|
||||
// eat '='
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
token = SharedGetToken();
|
||||
if (strcmp( "=", token ))
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
|
||||
// get attribute value
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected attribute value\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
token = SharedGetToken();
|
||||
|
||||
const char *decoratedName = GetDecoratedSkinName( skinName, filename );
|
||||
bool skinExists = GetCustomSkinIndex( decoratedName ) > 0;
|
||||
if ( m_nextSkin < NumCustomSkins && !skinExists )
|
||||
{
|
||||
// decorate the name
|
||||
m_skins[ m_nextSkin ] = CloneString( decoratedName );
|
||||
|
||||
// construct the model filename
|
||||
m_skinModelnames[ m_nextSkin ] = CloneString( token );
|
||||
m_skinFilenames[ m_nextSkin ] = new char[ strlen(token)*2 + strlen("models/player//.mdl") + 1 ];
|
||||
Q_snprintf( m_skinFilenames[ m_nextSkin ], sizeof( m_skinFilenames[ m_nextSkin ] ), "models/player/%s/%s.mdl", token, token );
|
||||
++m_nextSkin;
|
||||
}
|
||||
|
||||
// eat 'End'
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected 'End'\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
token = SharedGetToken();
|
||||
if (strcmp( "End", token ))
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected 'End'\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
|
||||
continue; // it's just a custom skin - no need to do inheritance on a bot profile, etc.
|
||||
}
|
||||
|
||||
// encountered a new profile
|
||||
BotProfile *profile;
|
||||
|
||||
if (isDefault)
|
||||
{
|
||||
profile = &defaultProfile;
|
||||
}
|
||||
else
|
||||
{
|
||||
profile = new BotProfile;
|
||||
|
||||
// always inherit from Default
|
||||
*profile = defaultProfile;
|
||||
}
|
||||
|
||||
// do inheritance in order of appearance
|
||||
if (!isTemplate && !isDefault)
|
||||
{
|
||||
const BotProfile *inherit = NULL;
|
||||
|
||||
// template names are separated by "+"
|
||||
while(true)
|
||||
{
|
||||
char *c = strchr( token, '+' );
|
||||
if (c)
|
||||
*c = '\000';
|
||||
|
||||
// find the given template name
|
||||
FOR_EACH_LL( m_templateList, it )
|
||||
{
|
||||
BotProfile *profile = m_templateList[ it ];
|
||||
if (!stricmp( profile->GetName(), token ))
|
||||
{
|
||||
inherit = profile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (inherit == NULL)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing '%s' - invalid template reference '%s'\n", filename, token );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
|
||||
// inherit the data
|
||||
profile->Inherit( inherit, &defaultProfile );
|
||||
|
||||
if (c == NULL)
|
||||
break;
|
||||
|
||||
token = c+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// get name of this profile
|
||||
if (!isDefault)
|
||||
{
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing '%s' - expected name\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
profile->m_name = CloneString( SharedGetToken() );
|
||||
|
||||
/**
|
||||
* HACK HACK
|
||||
* Until we have a generalized means of storing bot preferences, we're going to hardcode the bot's
|
||||
* preference towards silencers based on his name.
|
||||
*/
|
||||
if ( profile->m_name[0] % 2 )
|
||||
{
|
||||
profile->m_prefersSilencer = true;
|
||||
}
|
||||
}
|
||||
|
||||
// read attributes for this profile
|
||||
bool isFirstWeaponPref = true;
|
||||
while( true )
|
||||
{
|
||||
// get next token
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected 'End'\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
token = SharedGetToken();
|
||||
|
||||
// check for End delimiter
|
||||
if (!stricmp( token, "End" ))
|
||||
break;
|
||||
|
||||
// found attribute name - keep it
|
||||
char attributeName[64];
|
||||
strcpy( attributeName, token );
|
||||
|
||||
// eat '='
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
|
||||
token = SharedGetToken();
|
||||
if (strcmp( "=", token ))
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
|
||||
// get attribute value
|
||||
dataFile = SharedParse( dataFile );
|
||||
if (!dataFile)
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - expected attribute value\n", filename );
|
||||
delete [] dataPointer;
|
||||
return;
|
||||
}
|
||||
token = SharedGetToken();
|
||||
|
||||
// store value in appropriate attribute
|
||||
if (!stricmp( "Aggression", attributeName ))
|
||||
{
|
||||
profile->m_aggression = (float)atof(token) / 100.0f;
|
||||
}
|
||||
else if (!stricmp( "Skill", attributeName ))
|
||||
{
|
||||
profile->m_skill = (float)atof(token) / 100.0f;
|
||||
}
|
||||
else if (!stricmp( "Skin", attributeName ))
|
||||
{
|
||||
profile->m_skin = atoi(token);
|
||||
if ( profile->m_skin == 0 )
|
||||
{
|
||||
// atoi() failed - try to look up a custom skin by name
|
||||
profile->m_skin = GetCustomSkinIndex( token, filename );
|
||||
}
|
||||
}
|
||||
else if (!stricmp( "Teamwork", attributeName ))
|
||||
{
|
||||
profile->m_teamwork = (float)atof(token) / 100.0f;
|
||||
}
|
||||
else if (!stricmp( "Cost", attributeName ))
|
||||
{
|
||||
profile->m_cost = atoi(token);
|
||||
}
|
||||
else if (!stricmp( "VoicePitch", attributeName ))
|
||||
{
|
||||
profile->m_voicePitch = atoi(token);
|
||||
}
|
||||
else if (!stricmp( "VoiceBank", attributeName ))
|
||||
{
|
||||
profile->m_voiceBank = FindVoiceBankIndex( token );
|
||||
}
|
||||
else if (!stricmp( "WeaponPreference", attributeName ))
|
||||
{
|
||||
// weapon preferences override parent prefs
|
||||
if (isFirstWeaponPref)
|
||||
{
|
||||
isFirstWeaponPref = false;
|
||||
profile->m_weaponPreferenceCount = 0;
|
||||
}
|
||||
|
||||
if (!stricmp( token, "none" ))
|
||||
{
|
||||
profile->m_weaponPreferenceCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (profile->m_weaponPreferenceCount < BotProfile::MAX_WEAPON_PREFS)
|
||||
{
|
||||
profile->m_weaponPreference[ profile->m_weaponPreferenceCount++ ] = AliasToWeaponID( token );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!stricmp( "ReactionTime", attributeName ))
|
||||
{
|
||||
profile->m_reactionTime = (float)atof(token);
|
||||
|
||||
#ifndef GAMEUI_EXPORTS
|
||||
// subtract off latency due to "think" update rate.
|
||||
// In GameUI, we don't really care.
|
||||
//profile->m_reactionTime -= g_BotUpdateInterval;
|
||||
#endif
|
||||
|
||||
}
|
||||
else if (!stricmp( "AttackDelay", attributeName ))
|
||||
{
|
||||
profile->m_attackDelay = (float)atof(token);
|
||||
}
|
||||
else if (!stricmp( "Difficulty", attributeName ))
|
||||
{
|
||||
// override inheritance
|
||||
profile->m_difficultyFlags = 0;
|
||||
|
||||
// parse bit flags
|
||||
while(true)
|
||||
{
|
||||
char *c = strchr( token, '+' );
|
||||
if (c)
|
||||
*c = '\000';
|
||||
|
||||
for( int i=0; i<NUM_DIFFICULTY_LEVELS; ++i )
|
||||
if (!stricmp( BotDifficultyName[i], token ))
|
||||
profile->m_difficultyFlags |= (1 << i);
|
||||
|
||||
if (c == NULL)
|
||||
break;
|
||||
|
||||
token = c+1;
|
||||
}
|
||||
}
|
||||
else if (!stricmp( "Team", attributeName ))
|
||||
{
|
||||
if ( !stricmp( token, "T" ) )
|
||||
{
|
||||
profile->m_teams = TEAM_TERRORIST;
|
||||
}
|
||||
else if ( !stricmp( token, "CT" ) )
|
||||
{
|
||||
profile->m_teams = TEAM_CT;
|
||||
}
|
||||
else
|
||||
{
|
||||
profile->m_teams = TEAM_UNASSIGNED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CONSOLE_ECHO( "Error parsing %s - unknown attribute '%s'\n", filename, attributeName );
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDefault)
|
||||
{
|
||||
if (isTemplate)
|
||||
{
|
||||
// add to template list
|
||||
m_templateList.AddToTail( profile );
|
||||
}
|
||||
else
|
||||
{
|
||||
// add profile to the master list
|
||||
m_profileList.AddToTail( profile );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete [] dataPointer;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
BotProfileManager::~BotProfileManager( void )
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Free all bot profiles
|
||||
*/
|
||||
void BotProfileManager::Reset( void )
|
||||
{
|
||||
m_profileList.PurgeAndDeleteElements();
|
||||
m_templateList.PurgeAndDeleteElements();
|
||||
|
||||
int i;
|
||||
|
||||
for (i=0; i<NumCustomSkins; ++i)
|
||||
{
|
||||
if ( m_skins[i] )
|
||||
{
|
||||
delete[] m_skins[i];
|
||||
m_skins[i] = NULL;
|
||||
}
|
||||
if ( m_skinFilenames[i] )
|
||||
{
|
||||
delete[] m_skinFilenames[i];
|
||||
m_skinFilenames[i] = NULL;
|
||||
}
|
||||
if ( m_skinModelnames[i] )
|
||||
{
|
||||
delete[] m_skinModelnames[i];
|
||||
m_skinModelnames[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for ( i=0; i<m_voiceBanks.Count(); ++i )
|
||||
{
|
||||
delete[] m_voiceBanks[i];
|
||||
}
|
||||
m_voiceBanks.RemoveAll();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns custom skin name at a particular index
|
||||
*/
|
||||
const char * BotProfileManager::GetCustomSkin( int index )
|
||||
{
|
||||
if ( index < FirstCustomSkin || index > LastCustomSkin )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_skins[ index - FirstCustomSkin ];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns custom skin filename at a particular index
|
||||
*/
|
||||
const char * BotProfileManager::GetCustomSkinFname( int index )
|
||||
{
|
||||
if ( index < FirstCustomSkin || index > LastCustomSkin )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_skinFilenames[ index - FirstCustomSkin ];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns custom skin modelname at a particular index
|
||||
*/
|
||||
const char * BotProfileManager::GetCustomSkinModelname( int index )
|
||||
{
|
||||
if ( index < FirstCustomSkin || index > LastCustomSkin )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_skinModelnames[ index - FirstCustomSkin ];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Looks up a custom skin index by filename-decorated name (will decorate the name if filename is given)
|
||||
*/
|
||||
int BotProfileManager::GetCustomSkinIndex( const char *name, const char *filename )
|
||||
{
|
||||
const char * skinName = name;
|
||||
if ( filename )
|
||||
{
|
||||
skinName = GetDecoratedSkinName( name, filename );
|
||||
}
|
||||
|
||||
for (int i=0; i<NumCustomSkins; ++i)
|
||||
{
|
||||
if ( m_skins[i] )
|
||||
{
|
||||
if ( !stricmp( skinName, m_skins[i] ) )
|
||||
{
|
||||
return FirstCustomSkin + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* return index of the (custom) bot phrase db, inserting it if needed
|
||||
*/
|
||||
int BotProfileManager::FindVoiceBankIndex( const char *filename )
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
for ( int i=0; i<m_voiceBanks.Count(); ++i )
|
||||
{
|
||||
if ( !stricmp( filename, m_voiceBanks[i] ) )
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
m_voiceBanks.AddToTail( CloneString( filename ) );
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return random unused profile that matches the given difficulty level
|
||||
*/
|
||||
const BotProfile *BotProfileManager::GetRandomProfile( BotDifficultyType difficulty, int team, CSWeaponType weaponType ) const
|
||||
{
|
||||
// count up valid profiles
|
||||
CUtlVector< const BotProfile * > profiles;
|
||||
FOR_EACH_LL( m_profileList, it )
|
||||
{
|
||||
const BotProfile *profile = m_profileList[ it ];
|
||||
|
||||
// Match difficulty
|
||||
if ( !profile->IsDifficulty( difficulty ) )
|
||||
continue;
|
||||
|
||||
// Prevent duplicate names
|
||||
if ( UTIL_IsNameTaken( profile->GetName() ) )
|
||||
continue;
|
||||
|
||||
// Match team choice
|
||||
if ( !profile->IsValidForTeam( team ) )
|
||||
continue;
|
||||
|
||||
// Match desired weapon
|
||||
if ( weaponType != WEAPONTYPE_UNKNOWN )
|
||||
{
|
||||
if ( !profile->GetWeaponPreferenceCount() )
|
||||
continue;
|
||||
|
||||
if ( weaponType != WeaponClassFromWeaponID( (CSWeaponID)profile->GetWeaponPreference( 0 ) ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
profiles.AddToTail( profile );
|
||||
}
|
||||
|
||||
if ( !profiles.Count() )
|
||||
return NULL;
|
||||
|
||||
// select one at random
|
||||
int which = RandomInt( 0, profiles.Count()-1 );
|
||||
return profiles[which];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Michael S. Booth (mike@turtlerockstudios.com), 2003
|
||||
|
||||
#ifndef _BOT_PROFILE_H_
|
||||
#define _BOT_PROFILE_H_
|
||||
|
||||
#pragma warning( disable : 4786 ) // long STL names get truncated in browse info.
|
||||
|
||||
#include "bot_constants.h"
|
||||
#include "bot_util.h"
|
||||
#include "cs_weapon_parse.h"
|
||||
|
||||
enum
|
||||
{
|
||||
FirstCustomSkin = 100,
|
||||
NumCustomSkins = 100,
|
||||
LastCustomSkin = FirstCustomSkin + NumCustomSkins - 1,
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* A BotProfile describes the "personality" of a given bot
|
||||
*/
|
||||
class BotProfile
|
||||
{
|
||||
public:
|
||||
BotProfile( void )
|
||||
{
|
||||
m_name = NULL;
|
||||
m_aggression = 0.0f;
|
||||
m_skill = 0.0f;
|
||||
m_teamwork = 0.0f;
|
||||
m_weaponPreferenceCount = 0;
|
||||
m_cost = 0;
|
||||
m_skin = 0;
|
||||
m_difficultyFlags = 0;
|
||||
m_voicePitch = 100;
|
||||
m_reactionTime = 0.3f;
|
||||
m_attackDelay = 0.0f;
|
||||
m_teams = TEAM_UNASSIGNED;
|
||||
m_voiceBank = 0;
|
||||
m_prefersSilencer = false;
|
||||
}
|
||||
|
||||
~BotProfile( void )
|
||||
{
|
||||
if ( m_name )
|
||||
delete [] m_name;
|
||||
}
|
||||
|
||||
const char *GetName( void ) const { return m_name; } ///< return bot's name
|
||||
float GetAggression( void ) const { return m_aggression; }
|
||||
float GetSkill( void ) const { return m_skill; }
|
||||
float GetTeamwork( void ) const { return m_teamwork; }
|
||||
|
||||
CSWeaponID GetWeaponPreference( int i ) const { return m_weaponPreference[ i ]; }
|
||||
const char *GetWeaponPreferenceAsString( int i ) const;
|
||||
int GetWeaponPreferenceCount( void ) const { return m_weaponPreferenceCount; }
|
||||
bool HasPrimaryPreference( void ) const; ///< return true if this profile has a primary weapon preference
|
||||
bool HasPistolPreference( void ) const; ///< return true if this profile has a pistol weapon preference
|
||||
|
||||
int GetCost( void ) const { return m_cost; }
|
||||
int GetSkin( void ) const { return m_skin; }
|
||||
bool IsDifficulty( BotDifficultyType diff ) const; ///< return true if this profile can be used for the given difficulty level
|
||||
int GetVoicePitch( void ) const { return m_voicePitch; }
|
||||
float GetReactionTime( void ) const { return m_reactionTime; }
|
||||
float GetAttackDelay( void ) const { return m_attackDelay; }
|
||||
int GetVoiceBank() const { return m_voiceBank; }
|
||||
|
||||
bool IsValidForTeam( int team ) const;
|
||||
|
||||
bool PrefersSilencer() const { return m_prefersSilencer; }
|
||||
|
||||
bool InheritsFrom( const char *name ) const;
|
||||
|
||||
private:
|
||||
friend class BotProfileManager; ///< for loading profiles
|
||||
|
||||
void Inherit( const BotProfile *parent, const BotProfile *baseline ); ///< copy values from parent if they differ from baseline
|
||||
|
||||
char *m_name; ///< the bot's name
|
||||
float m_aggression; ///< percentage: 0 = coward, 1 = berserker
|
||||
float m_skill; ///< percentage: 0 = terrible, 1 = expert
|
||||
float m_teamwork; ///< percentage: 0 = rogue, 1 = complete obeyance to team, lots of comm
|
||||
|
||||
enum { MAX_WEAPON_PREFS = 16 };
|
||||
CSWeaponID m_weaponPreference[ MAX_WEAPON_PREFS ]; ///< which weapons this bot likes to use, in order of priority
|
||||
int m_weaponPreferenceCount;
|
||||
|
||||
int m_cost; ///< reputation point cost for career mode
|
||||
int m_skin; ///< "skin" index
|
||||
unsigned char m_difficultyFlags; ///< bits set correspond to difficulty levels this is valid for
|
||||
int m_voicePitch; ///< the pitch shift for bot chatter (100 = normal)
|
||||
float m_reactionTime; //< our reaction time in seconds
|
||||
float m_attackDelay; ///< time in seconds from when we notice an enemy to when we open fire
|
||||
int m_teams; ///< teams for which this profile is valid
|
||||
|
||||
bool m_prefersSilencer; ///< does the bot prefer to use silencers?
|
||||
|
||||
int m_voiceBank; ///< Index of the BotChatter.db voice bank this profile uses (0 is the default)
|
||||
|
||||
CUtlVector< const BotProfile * > m_templates; ///< List of templates we inherit from
|
||||
};
|
||||
typedef CUtlLinkedList<BotProfile *> BotProfileList;
|
||||
|
||||
|
||||
inline bool BotProfile::IsDifficulty( BotDifficultyType diff ) const
|
||||
{
|
||||
return (m_difficultyFlags & (1 << diff)) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy in data from parent if it differs from the baseline
|
||||
*/
|
||||
inline void BotProfile::Inherit( const BotProfile *parent, const BotProfile *baseline )
|
||||
{
|
||||
if (parent->m_aggression != baseline->m_aggression)
|
||||
m_aggression = parent->m_aggression;
|
||||
|
||||
if (parent->m_skill != baseline->m_skill)
|
||||
m_skill = parent->m_skill;
|
||||
|
||||
if (parent->m_teamwork != baseline->m_teamwork)
|
||||
m_teamwork = parent->m_teamwork;
|
||||
|
||||
if (parent->m_weaponPreferenceCount != baseline->m_weaponPreferenceCount)
|
||||
{
|
||||
m_weaponPreferenceCount = parent->m_weaponPreferenceCount;
|
||||
for( int i=0; i<parent->m_weaponPreferenceCount; ++i )
|
||||
m_weaponPreference[i] = parent->m_weaponPreference[i];
|
||||
}
|
||||
|
||||
if (parent->m_cost != baseline->m_cost)
|
||||
m_cost = parent->m_cost;
|
||||
|
||||
if (parent->m_skin != baseline->m_skin)
|
||||
m_skin = parent->m_skin;
|
||||
|
||||
if (parent->m_difficultyFlags != baseline->m_difficultyFlags)
|
||||
m_difficultyFlags = parent->m_difficultyFlags;
|
||||
|
||||
if (parent->m_voicePitch != baseline->m_voicePitch)
|
||||
m_voicePitch = parent->m_voicePitch;
|
||||
|
||||
if (parent->m_reactionTime != baseline->m_reactionTime)
|
||||
m_reactionTime = parent->m_reactionTime;
|
||||
|
||||
if (parent->m_attackDelay != baseline->m_attackDelay)
|
||||
m_attackDelay = parent->m_attackDelay;
|
||||
|
||||
if (parent->m_teams != baseline->m_teams)
|
||||
m_teams = parent->m_teams;
|
||||
|
||||
if (parent->m_voiceBank != baseline->m_voiceBank)
|
||||
m_voiceBank = parent->m_voiceBank;
|
||||
|
||||
m_templates.AddToTail( parent );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* The BotProfileManager defines the interface to accessing BotProfiles
|
||||
*/
|
||||
class BotProfileManager
|
||||
{
|
||||
public:
|
||||
BotProfileManager( void );
|
||||
~BotProfileManager( void );
|
||||
|
||||
void Init( const char *filename, unsigned int *checksum = NULL );
|
||||
void Reset( void );
|
||||
|
||||
/// given a name, return a profile
|
||||
const BotProfile *GetProfile( const char *name, int team ) const
|
||||
{
|
||||
FOR_EACH_LL( m_profileList, it )
|
||||
{
|
||||
BotProfile *profile = m_profileList[ it ];
|
||||
|
||||
if ( !stricmp( name, profile->GetName() ) && profile->IsValidForTeam( team ) )
|
||||
return profile;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// given a template name and difficulty, return a profile
|
||||
const BotProfile *GetProfileMatchingTemplate( const char *profileName, int team, BotDifficultyType difficulty ) const
|
||||
{
|
||||
FOR_EACH_LL( m_profileList, it )
|
||||
{
|
||||
BotProfile *profile = m_profileList[ it ];
|
||||
|
||||
if ( !profile->InheritsFrom( profileName ) )
|
||||
continue;
|
||||
|
||||
if ( !profile->IsValidForTeam( team ) )
|
||||
continue;
|
||||
|
||||
if ( !profile->IsDifficulty( difficulty ) )
|
||||
continue;
|
||||
|
||||
if ( UTIL_IsNameTaken( profile->GetName() ) )
|
||||
continue;
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const BotProfileList *GetProfileList( void ) const { return &m_profileList; } ///< return list of all profiles
|
||||
|
||||
const BotProfile *GetRandomProfile( BotDifficultyType difficulty, int team, CSWeaponType weaponType ) const; ///< return random unused profile that matches the given difficulty level
|
||||
|
||||
const char * GetCustomSkin( int index ); ///< Returns custom skin name at a particular index
|
||||
const char * GetCustomSkinModelname( int index ); ///< Returns custom skin modelname at a particular index
|
||||
const char * GetCustomSkinFname( int index ); ///< Returns custom skin filename at a particular index
|
||||
int GetCustomSkinIndex( const char *name, const char *filename = NULL ); ///< Looks up a custom skin index by name
|
||||
|
||||
typedef CUtlVector<char *> VoiceBankList;
|
||||
const VoiceBankList *GetVoiceBanks( void ) const { return &m_voiceBanks; }
|
||||
int FindVoiceBankIndex( const char *filename ); ///< return index of the (custom) bot phrase db, inserting it if needed
|
||||
|
||||
protected:
|
||||
BotProfileList m_profileList; ///< the list of all bot profiles
|
||||
BotProfileList m_templateList; ///< the list of all bot templates
|
||||
|
||||
VoiceBankList m_voiceBanks;
|
||||
|
||||
char *m_skins[ NumCustomSkins ]; ///< Custom skin names
|
||||
char *m_skinModelnames[ NumCustomSkins ]; ///< Custom skin modelnames
|
||||
char *m_skinFilenames[ NumCustomSkins ]; ///< Custom skin filenames
|
||||
int m_nextSkin; ///< Next custom skin to allocate
|
||||
};
|
||||
|
||||
/// the global singleton for accessing BotProfiles
|
||||
extern BotProfileManager *TheBotProfiles;
|
||||
|
||||
|
||||
#endif // _BOT_PROFILE_H_
|
||||
@@ -0,0 +1,604 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Michael S. Booth (mike@turtlerockstudios.com), 2003
|
||||
|
||||
#include "cbase.h"
|
||||
#include "cs_shareddefs.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "KeyValues.h"
|
||||
|
||||
#include "bot.h"
|
||||
#include "bot_util.h"
|
||||
#include "bot_profile.h"
|
||||
|
||||
#include "cs_bot.h"
|
||||
#include <ctype.h>
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
static int s_iBeamSprite = 0;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if given name is already in use by another player
|
||||
*/
|
||||
bool UTIL_IsNameTaken( const char *name, bool ignoreHumans )
|
||||
{
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (player == NULL)
|
||||
continue;
|
||||
|
||||
if (player->IsPlayer() && player->IsBot())
|
||||
{
|
||||
// bots can have prefixes so we need to check the name
|
||||
// against the profile name instead.
|
||||
CCSBot *bot = dynamic_cast<CCSBot *>(player);
|
||||
if ( bot && bot->GetProfile()->GetName() && FStrEq(name, bot->GetProfile()->GetName()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ignoreHumans)
|
||||
{
|
||||
if (FStrEq( name, player->GetPlayerName() ))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
int UTIL_ClientsInGame( void )
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBaseEntity *player = UTIL_PlayerByIndex( i );
|
||||
|
||||
if (player == NULL)
|
||||
continue;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return the number of non-bots on the given team
|
||||
*/
|
||||
int UTIL_HumansOnTeam( int teamID, bool isAlive )
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBaseEntity *entity = UTIL_PlayerByIndex( i );
|
||||
|
||||
if ( entity == NULL )
|
||||
continue;
|
||||
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( entity );
|
||||
|
||||
if (player->IsBot())
|
||||
continue;
|
||||
|
||||
if (player->GetTeamNumber() != teamID)
|
||||
continue;
|
||||
|
||||
if (isAlive && !player->IsAlive())
|
||||
continue;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
int UTIL_BotsInGame( void )
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>(UTIL_PlayerByIndex( i ));
|
||||
|
||||
if ( player == NULL )
|
||||
continue;
|
||||
|
||||
if ( !player->IsBot() )
|
||||
continue;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Kick a bot from the given team. If no bot exists on the team, return false.
|
||||
*/
|
||||
bool UTIL_KickBotFromTeam( int kickTeam )
|
||||
{
|
||||
int i;
|
||||
|
||||
// try to kick a dead bot first
|
||||
for ( i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (player == NULL)
|
||||
continue;
|
||||
|
||||
if (!player->IsBot())
|
||||
continue;
|
||||
|
||||
if (!player->IsAlive() && player->GetTeamNumber() == kickTeam)
|
||||
{
|
||||
// its a bot on the right team - kick it
|
||||
engine->ServerCommand( UTIL_VarArgs( "kick \"%s\"\n", player->GetPlayerName() ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// no dead bots, kick any bot on the given team
|
||||
for ( i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (player == NULL)
|
||||
continue;
|
||||
|
||||
if (!player->IsBot())
|
||||
continue;
|
||||
|
||||
if (player->GetTeamNumber() == kickTeam)
|
||||
{
|
||||
// its a bot on the right team - kick it
|
||||
engine->ServerCommand( UTIL_VarArgs( "kick \"%s\"\n", player->GetPlayerName() ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if all of the members of the given team are bots
|
||||
*/
|
||||
bool UTIL_IsTeamAllBots( int team )
|
||||
{
|
||||
int botCount = 0;
|
||||
|
||||
for( int i=1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (player == NULL)
|
||||
continue;
|
||||
|
||||
// skip players on other teams
|
||||
if (player->GetTeamNumber() != team)
|
||||
continue;
|
||||
|
||||
// if not a bot, fail the test
|
||||
if (!player->IsBot())
|
||||
return false;
|
||||
|
||||
// is a bot on given team
|
||||
++botCount;
|
||||
}
|
||||
|
||||
// if team is empty, there are no bots
|
||||
return (botCount) ? true : false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return the closest active player to the given position.
|
||||
* If 'distance' is non-NULL, the distance to the closest player is returned in it.
|
||||
*/
|
||||
extern CBasePlayer *UTIL_GetClosestPlayer( const Vector &pos, float *distance )
|
||||
{
|
||||
CBasePlayer *closePlayer = NULL;
|
||||
float closeDistSq = 999999999999.9f;
|
||||
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (!IsEntityValid( player ))
|
||||
continue;
|
||||
|
||||
if (!player->IsAlive())
|
||||
continue;
|
||||
|
||||
Vector playerOrigin = GetCentroid( player );
|
||||
float distSq = (playerOrigin - pos).LengthSqr();
|
||||
if (distSq < closeDistSq)
|
||||
{
|
||||
closeDistSq = distSq;
|
||||
closePlayer = static_cast<CBasePlayer *>( player );
|
||||
}
|
||||
}
|
||||
|
||||
if (distance)
|
||||
*distance = (float)sqrt( closeDistSq );
|
||||
|
||||
return closePlayer;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return the closest active player on the given team to the given position.
|
||||
* If 'distance' is non-NULL, the distance to the closest player is returned in it.
|
||||
*/
|
||||
extern CBasePlayer *UTIL_GetClosestPlayer( const Vector &pos, int team, float *distance )
|
||||
{
|
||||
CBasePlayer *closePlayer = NULL;
|
||||
float closeDistSq = 999999999999.9f;
|
||||
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (!IsEntityValid( player ))
|
||||
continue;
|
||||
|
||||
if (!player->IsAlive())
|
||||
continue;
|
||||
|
||||
if (player->GetTeamNumber() != team)
|
||||
continue;
|
||||
|
||||
Vector playerOrigin = GetCentroid( player );
|
||||
float distSq = (playerOrigin - pos).LengthSqr();
|
||||
if (distSq < closeDistSq)
|
||||
{
|
||||
closeDistSq = distSq;
|
||||
closePlayer = static_cast<CBasePlayer *>( player );
|
||||
}
|
||||
}
|
||||
|
||||
if (distance)
|
||||
*distance = (float)sqrt( closeDistSq );
|
||||
|
||||
return closePlayer;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
// Takes the bot pointer and constructs the net name using the current bot name prefix.
|
||||
void UTIL_ConstructBotNetName( char *name, int nameLength, const BotProfile *profile )
|
||||
{
|
||||
if (profile == NULL)
|
||||
{
|
||||
name[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// if there is no bot prefix just use the profile name.
|
||||
if ((cv_bot_prefix.GetString() == NULL) || (strlen(cv_bot_prefix.GetString()) == 0))
|
||||
{
|
||||
Q_strncpy( name, profile->GetName(), nameLength );
|
||||
return;
|
||||
}
|
||||
|
||||
// find the highest difficulty
|
||||
const char *diffStr = BotDifficultyName[0];
|
||||
for ( int i=BOT_EXPERT; i>0; --i )
|
||||
{
|
||||
if ( profile->IsDifficulty( (BotDifficultyType)i ) )
|
||||
{
|
||||
diffStr = BotDifficultyName[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char *weaponStr = NULL;
|
||||
if ( profile->GetWeaponPreferenceCount() )
|
||||
{
|
||||
weaponStr = profile->GetWeaponPreferenceAsString( 0 );
|
||||
|
||||
const char *translatedAlias = GetTranslatedWeaponAlias( weaponStr );
|
||||
|
||||
char wpnName[128];
|
||||
Q_snprintf( wpnName, sizeof( wpnName ), "weapon_%s", translatedAlias );
|
||||
WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( wpnName );
|
||||
if ( hWpnInfo != GetInvalidWeaponInfoHandle() )
|
||||
{
|
||||
CCSWeaponInfo *pWeaponInfo = dynamic_cast< CCSWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
|
||||
if ( pWeaponInfo )
|
||||
{
|
||||
CSWeaponType weaponType = pWeaponInfo->m_WeaponType;
|
||||
weaponStr = WeaponClassAsString( weaponType );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !weaponStr )
|
||||
{
|
||||
weaponStr = "";
|
||||
}
|
||||
|
||||
char skillStr[16];
|
||||
Q_snprintf( skillStr, sizeof( skillStr ), "%.0f", profile->GetSkill()*100 );
|
||||
|
||||
char temp[MAX_PLAYER_NAME_LENGTH*2];
|
||||
char prefix[MAX_PLAYER_NAME_LENGTH*2];
|
||||
Q_strncpy( temp, cv_bot_prefix.GetString(), sizeof( temp ) );
|
||||
Q_StrSubst( temp, "<difficulty>", diffStr, prefix, sizeof( prefix ) );
|
||||
Q_StrSubst( prefix, "<weaponclass>", weaponStr, temp, sizeof( temp ) );
|
||||
Q_StrSubst( temp, "<skill>", skillStr, prefix, sizeof( prefix ) );
|
||||
Q_snprintf( name, nameLength, "%s %s", prefix, profile->GetName() );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if anyone on the given team can see the given spot
|
||||
*/
|
||||
bool UTIL_IsVisibleToTeam( const Vector &spot, int team )
|
||||
{
|
||||
for( int i = 1; i <= gpGlobals->maxClients; ++i )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if (player == NULL)
|
||||
continue;
|
||||
|
||||
if (!player->IsAlive())
|
||||
continue;
|
||||
|
||||
if (player->GetTeamNumber() != team)
|
||||
continue;
|
||||
|
||||
trace_t result;
|
||||
UTIL_TraceLine( player->EyePosition(), spot, CONTENTS_SOLID, player, COLLISION_GROUP_NONE, &result );
|
||||
|
||||
if (result.fraction == 1.0f)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
void UTIL_DrawBeamFromEnt( int i, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue )
|
||||
{
|
||||
/* BOTPORT: What is the replacement for MESSAGE_BEGIN?
|
||||
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecEnd ); // vecEnd = origin???
|
||||
WRITE_BYTE( TE_BEAMENTPOINT );
|
||||
WRITE_SHORT( i );
|
||||
WRITE_COORD( vecEnd.x );
|
||||
WRITE_COORD( vecEnd.y );
|
||||
WRITE_COORD( vecEnd.z );
|
||||
WRITE_SHORT( s_iBeamSprite );
|
||||
WRITE_BYTE( 0 ); // startframe
|
||||
WRITE_BYTE( 0 ); // framerate
|
||||
WRITE_BYTE( iLifetime ); // life
|
||||
WRITE_BYTE( 10 ); // width
|
||||
WRITE_BYTE( 0 ); // noise
|
||||
WRITE_BYTE( bRed ); // r, g, b
|
||||
WRITE_BYTE( bGreen ); // r, g, b
|
||||
WRITE_BYTE( bBlue ); // r, g, b
|
||||
WRITE_BYTE( 255 ); // brightness
|
||||
WRITE_BYTE( 0 ); // speed
|
||||
MESSAGE_END();
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
void UTIL_DrawBeamPoints( Vector vecStart, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue )
|
||||
{
|
||||
NDebugOverlay::Line( vecStart, vecEnd, bRed, bGreen, bBlue, true, 0.1f );
|
||||
|
||||
/*
|
||||
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecStart );
|
||||
WRITE_BYTE( TE_BEAMPOINTS );
|
||||
WRITE_COORD( vecStart.x );
|
||||
WRITE_COORD( vecStart.y );
|
||||
WRITE_COORD( vecStart.z );
|
||||
WRITE_COORD( vecEnd.x );
|
||||
WRITE_COORD( vecEnd.y );
|
||||
WRITE_COORD( vecEnd.z );
|
||||
WRITE_SHORT( s_iBeamSprite );
|
||||
WRITE_BYTE( 0 ); // startframe
|
||||
WRITE_BYTE( 0 ); // framerate
|
||||
WRITE_BYTE( iLifetime ); // life
|
||||
WRITE_BYTE( 10 ); // width
|
||||
WRITE_BYTE( 0 ); // noise
|
||||
WRITE_BYTE( bRed ); // r, g, b
|
||||
WRITE_BYTE( bGreen ); // r, g, b
|
||||
WRITE_BYTE( bBlue ); // r, g, b
|
||||
WRITE_BYTE( 255 ); // brightness
|
||||
WRITE_BYTE( 0 ); // speed
|
||||
MESSAGE_END();
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
void CONSOLE_ECHO( const char * pszMsg, ... )
|
||||
{
|
||||
va_list argptr;
|
||||
static char szStr[1024];
|
||||
|
||||
va_start( argptr, pszMsg );
|
||||
vsprintf( szStr, pszMsg, argptr );
|
||||
va_end( argptr );
|
||||
|
||||
Msg( "%s", szStr );
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
void BotPrecache( void )
|
||||
{
|
||||
s_iBeamSprite = CBaseEntity::PrecacheModel( "sprites/smoke.spr" );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
#define COS_TABLE_SIZE 256
|
||||
static float cosTable[ COS_TABLE_SIZE ];
|
||||
|
||||
void InitBotTrig( void )
|
||||
{
|
||||
for( int i=0; i<COS_TABLE_SIZE; ++i )
|
||||
{
|
||||
float angle = (float)(2.0f * M_PI * i / (float)(COS_TABLE_SIZE-1));
|
||||
cosTable[i] = (float)cos( angle );
|
||||
}
|
||||
}
|
||||
|
||||
float BotCOS( float angle )
|
||||
{
|
||||
angle = AngleNormalizePositive( angle );
|
||||
int i = (int)( angle * (COS_TABLE_SIZE-1) / 360.0f );
|
||||
return cosTable[i];
|
||||
}
|
||||
|
||||
float BotSIN( float angle )
|
||||
{
|
||||
angle = AngleNormalizePositive( angle - 90 );
|
||||
int i = (int)( angle * (COS_TABLE_SIZE-1) / 360.0f );
|
||||
return cosTable[i];
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Send a "hint" message to all players, dead or alive.
|
||||
*/
|
||||
void HintMessageToAllPlayers( const char *message )
|
||||
{
|
||||
hudtextparms_t textParms;
|
||||
|
||||
textParms.x = -1.0f;
|
||||
textParms.y = -1.0f;
|
||||
textParms.fadeinTime = 1.0f;
|
||||
textParms.fadeoutTime = 5.0f;
|
||||
textParms.holdTime = 5.0f;
|
||||
textParms.fxTime = 0.0f;
|
||||
textParms.r1 = 100;
|
||||
textParms.g1 = 255;
|
||||
textParms.b1 = 100;
|
||||
textParms.r2 = 255;
|
||||
textParms.g2 = 255;
|
||||
textParms.b2 = 255;
|
||||
textParms.effect = 0;
|
||||
textParms.channel = 0;
|
||||
|
||||
UTIL_HudMessageAll( textParms, message );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if moving from "start" to "finish" will cross a player's line of fire.
|
||||
* The path from "start" to "finish" is assumed to be a straight line.
|
||||
* "start" and "finish" are assumed to be points on the ground.
|
||||
*/
|
||||
bool IsCrossingLineOfFire( const Vector &start, const Vector &finish, CBaseEntity *ignore, int ignoreTeam )
|
||||
{
|
||||
for ( int p=1; p <= gpGlobals->maxClients; ++p )
|
||||
{
|
||||
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( p ) );
|
||||
|
||||
if (!IsEntityValid( player ))
|
||||
continue;
|
||||
|
||||
if (player == ignore)
|
||||
continue;
|
||||
|
||||
if (!player->IsAlive())
|
||||
continue;
|
||||
|
||||
if (ignoreTeam && player->GetTeamNumber() == ignoreTeam)
|
||||
continue;
|
||||
|
||||
// compute player's unit aiming vector
|
||||
Vector viewForward;
|
||||
AngleVectors( player->EyeAngles() + player->GetPunchAngle(), &viewForward );
|
||||
|
||||
const float longRange = 5000.0f;
|
||||
Vector playerOrigin = GetCentroid( player );
|
||||
Vector playerTarget = playerOrigin + longRange * viewForward;
|
||||
|
||||
Vector result( 0, 0, 0 );
|
||||
if (IsIntersecting2D( start, finish, playerOrigin, playerTarget, &result ))
|
||||
{
|
||||
// simple check to see if intersection lies in the Z range of the path
|
||||
float loZ, hiZ;
|
||||
|
||||
if (start.z < finish.z)
|
||||
{
|
||||
loZ = start.z;
|
||||
hiZ = finish.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
loZ = finish.z;
|
||||
hiZ = start.z;
|
||||
}
|
||||
|
||||
if (result.z >= loZ && result.z <= hiZ + HumanHeight)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Performs a simple case-insensitive string comparison, honoring trailing * wildcards
|
||||
*/
|
||||
bool WildcardMatch( const char *query, const char *test )
|
||||
{
|
||||
if ( !query || !test )
|
||||
return false;
|
||||
|
||||
while ( *test && *query )
|
||||
{
|
||||
char nameChar = *test;
|
||||
char queryChar = *query;
|
||||
if ( tolower(nameChar) != tolower(queryChar) ) // case-insensitive
|
||||
break;
|
||||
++test;
|
||||
++query;
|
||||
}
|
||||
|
||||
if ( *query == 0 && *test == 0 )
|
||||
return true;
|
||||
|
||||
// Support trailing *
|
||||
if ( *query == '*' )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BOT_UTIL_H
|
||||
#define BOT_UTIL_H
|
||||
|
||||
|
||||
#include "convar.h"
|
||||
#include "util.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
enum PriorityType
|
||||
{
|
||||
PRIORITY_LOW, PRIORITY_MEDIUM, PRIORITY_HIGH, PRIORITY_UNINTERRUPTABLE
|
||||
};
|
||||
|
||||
|
||||
extern ConVar cv_bot_traceview;
|
||||
extern ConVar cv_bot_stop;
|
||||
extern ConVar cv_bot_show_nav;
|
||||
extern ConVar cv_bot_walk;
|
||||
extern ConVar cv_bot_difficulty;
|
||||
extern ConVar cv_bot_debug;
|
||||
extern ConVar cv_bot_debug_target;
|
||||
extern ConVar cv_bot_quota;
|
||||
extern ConVar cv_bot_quota_mode;
|
||||
extern ConVar cv_bot_prefix;
|
||||
extern ConVar cv_bot_allow_rogues;
|
||||
extern ConVar cv_bot_allow_pistols;
|
||||
extern ConVar cv_bot_allow_shotguns;
|
||||
extern ConVar cv_bot_allow_sub_machine_guns;
|
||||
extern ConVar cv_bot_allow_rifles;
|
||||
extern ConVar cv_bot_allow_machine_guns;
|
||||
extern ConVar cv_bot_allow_grenades;
|
||||
extern ConVar cv_bot_allow_snipers;
|
||||
extern ConVar cv_bot_allow_shield;
|
||||
extern ConVar cv_bot_join_team;
|
||||
extern ConVar cv_bot_join_after_player;
|
||||
extern ConVar cv_bot_auto_vacate;
|
||||
extern ConVar cv_bot_zombie;
|
||||
extern ConVar cv_bot_defer_to_human;
|
||||
extern ConVar cv_bot_chatter;
|
||||
extern ConVar cv_bot_profile_db;
|
||||
extern ConVar cv_bot_dont_shoot;
|
||||
extern ConVar cv_bot_eco_limit;
|
||||
extern ConVar cv_bot_auto_follow;
|
||||
extern ConVar cv_bot_flipout;
|
||||
|
||||
#define RAD_TO_DEG( deg ) ((deg) * 180.0 / M_PI)
|
||||
#define DEG_TO_RAD( rad ) ((rad) * M_PI / 180.0)
|
||||
|
||||
#define SIGN( num ) (((num) < 0) ? -1 : 1)
|
||||
#define ABS( num ) (SIGN(num) * (num))
|
||||
|
||||
|
||||
#define CREATE_FAKE_CLIENT ( *g_engfuncs.pfnCreateFakeClient )
|
||||
#define GET_USERINFO ( *g_engfuncs.pfnGetInfoKeyBuffer )
|
||||
#define SET_KEY_VALUE ( *g_engfuncs.pfnSetKeyValue )
|
||||
#define SET_CLIENT_KEY_VALUE ( *g_engfuncs.pfnSetClientKeyValue )
|
||||
|
||||
class BotProfile;
|
||||
|
||||
extern void BotPrecache( void );
|
||||
extern int UTIL_ClientsInGame( void );
|
||||
|
||||
extern bool UTIL_IsNameTaken( const char *name, bool ignoreHumans = false ); ///< return true if given name is already in use by another player
|
||||
|
||||
#define IS_ALIVE true
|
||||
extern int UTIL_HumansOnTeam( int teamID, bool isAlive = false );
|
||||
|
||||
extern int UTIL_BotsInGame( void );
|
||||
extern bool UTIL_IsTeamAllBots( int team );
|
||||
extern void UTIL_DrawBeamFromEnt( int iIndex, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue );
|
||||
extern void UTIL_DrawBeamPoints( Vector vecStart, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue );
|
||||
extern CBasePlayer *UTIL_GetClosestPlayer( const Vector &pos, float *distance = NULL );
|
||||
extern CBasePlayer *UTIL_GetClosestPlayer( const Vector &pos, int team, float *distance = NULL );
|
||||
extern bool UTIL_KickBotFromTeam( int kickTeam ); ///< kick a bot from the given team. If no bot exists on the team, return false.
|
||||
|
||||
extern bool UTIL_IsVisibleToTeam( const Vector &spot, int team ); ///< return true if anyone on the given team can see the given spot
|
||||
|
||||
/// return true if moving from "start" to "finish" will cross a player's line of fire.
|
||||
extern bool IsCrossingLineOfFire( const Vector &start, const Vector &finish, CBaseEntity *ignore = NULL, int ignoreTeam = 0 );
|
||||
|
||||
extern void UTIL_ConstructBotNetName(char *name, int nameLength, const BotProfile *bot); ///< constructs a complete name including prefix
|
||||
|
||||
/**
|
||||
* Echos text to the console, and prints it on the client's screen. This is NOT tied to the developer cvar.
|
||||
* If you are adding debugging output in cstrike, use UTIL_DPrintf() (debug.h) instead.
|
||||
*/
|
||||
extern void CONSOLE_ECHO( PRINTF_FORMAT_STRING const char * pszMsg, ... );
|
||||
|
||||
extern void InitBotTrig( void );
|
||||
extern float BotCOS( float angle );
|
||||
extern float BotSIN( float angle );
|
||||
|
||||
extern void HintMessageToAllPlayers( const char *message );
|
||||
|
||||
bool WildcardMatch( const char *query, const char *test ); ///< Performs a simple case-insensitive string comparison, honoring trailing * wildcards
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Return true if the given entity is valid
|
||||
*/
|
||||
inline bool IsEntityValid( CBaseEntity *entity )
|
||||
{
|
||||
if (entity == NULL)
|
||||
return false;
|
||||
|
||||
if (FNullEnt( entity->edict() ))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Given two line segments: startA to endA, and startB to endB, return true if they intesect
|
||||
* and put the intersection point in "result".
|
||||
* Note that this computes the intersection of the 2D (x,y) projection of the line segments.
|
||||
*/
|
||||
inline bool IsIntersecting2D( const Vector &startA, const Vector &endA,
|
||||
const Vector &startB, const Vector &endB,
|
||||
Vector *result = NULL )
|
||||
{
|
||||
float denom = (endA.x - startA.x) * (endB.y - startB.y) - (endA.y - startA.y) * (endB.x - startB.x);
|
||||
if (denom == 0.0f)
|
||||
{
|
||||
// parallel
|
||||
return false;
|
||||
}
|
||||
|
||||
float numS = (startA.y - startB.y) * (endB.x - startB.x) - (startA.x - startB.x) * (endB.y - startB.y);
|
||||
if (numS == 0.0f)
|
||||
{
|
||||
// coincident
|
||||
return true;
|
||||
}
|
||||
|
||||
float numT = (startA.y - startB.y) * (endA.x - startA.x) - (startA.x - startB.x) * (endA.y - startA.y);
|
||||
|
||||
float s = numS / denom;
|
||||
if (s < 0.0f || s > 1.0f)
|
||||
{
|
||||
// intersection is not within line segment of startA to endA
|
||||
return false;
|
||||
}
|
||||
|
||||
float t = numT / denom;
|
||||
if (t < 0.0f || t > 1.0f)
|
||||
{
|
||||
// intersection is not within line segment of startB to endB
|
||||
return false;
|
||||
}
|
||||
|
||||
// compute intesection point
|
||||
if (result)
|
||||
*result = startA + s * (endA - startA);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// improv_locomotor.h
|
||||
// Interface for moving Improvs along computed paths
|
||||
// Author: Michael Booth, July 2004
|
||||
|
||||
#ifndef _IMPROV_LOCOMOTOR_H_
|
||||
#define _IMPROV_LOCOMOTOR_H_
|
||||
|
||||
// TODO: Remove duplicate methods from CImprov, and update CImprov to use this class
|
||||
|
||||
/**
|
||||
* A locomotor owns the movement of an Improv
|
||||
*/
|
||||
class CImprovLocomotor
|
||||
{
|
||||
public:
|
||||
virtual const Vector &GetCentroid( void ) const = 0;
|
||||
virtual const Vector &GetFeet( void ) const = 0; ///< return position of "feet" - point below centroid of improv at feet level
|
||||
virtual const Vector &GetEyes( void ) const = 0;
|
||||
virtual float GetMoveAngle( void ) const = 0; ///< return direction of movement
|
||||
|
||||
virtual CNavArea *GetLastKnownArea( void ) const = 0;
|
||||
virtual bool GetSimpleGroundHeightWithFloor( const Vector &pos, float *height, Vector *normal = NULL ) = 0; ///< find "simple" ground height, treating current nav area as part of the floor
|
||||
|
||||
virtual void Crouch( void ) = 0;
|
||||
virtual void StandUp( void ) = 0; ///< "un-crouch"
|
||||
virtual bool IsCrouching( void ) const = 0;
|
||||
|
||||
virtual void Jump( void ) = 0; ///< initiate a jump
|
||||
virtual bool IsJumping( void ) const = 0;
|
||||
|
||||
virtual void Run( void ) = 0; ///< set movement speed to running
|
||||
virtual void Walk( void ) = 0; ///< set movement speed to walking
|
||||
virtual bool IsRunning( void ) const = 0;
|
||||
|
||||
virtual void StartLadder( const CNavLadder *ladder, NavTraverseType how, const Vector &approachPos, const Vector &departPos ) = 0; ///< invoked when a ladder is encountered while following a path
|
||||
virtual bool TraverseLadder( const CNavLadder *ladder, NavTraverseType how, const Vector &approachPos, const Vector &departPos, float deltaT ) = 0; ///< traverse given ladder
|
||||
virtual bool IsUsingLadder( void ) const = 0;
|
||||
|
||||
enum MoveToFailureType
|
||||
{
|
||||
FAIL_INVALID_PATH,
|
||||
FAIL_STUCK,
|
||||
FAIL_FELL_OFF,
|
||||
};
|
||||
virtual void TrackPath( const Vector &pathGoal, float deltaT ) = 0; ///< move along path by following "pathGoal"
|
||||
virtual void OnMoveToSuccess( const Vector &goal ) { } ///< invoked when an improv reaches its MoveTo goal
|
||||
virtual void OnMoveToFailure( const Vector &goal, MoveToFailureType reason ) { } ///< invoked when an improv fails to reach a MoveTo goal
|
||||
};
|
||||
|
||||
#endif // _IMPROV_LOCOMOTOR_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,246 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// nav_path.h
|
||||
// Navigation Path encapsulation
|
||||
// Author: Michael S. Booth (mike@turtlerockstudios.com), November 2003
|
||||
|
||||
#ifndef _NAV_PATH_H_
|
||||
#define _NAV_PATH_H_
|
||||
|
||||
#include "cs_nav_area.h"
|
||||
#include "bot_util.h"
|
||||
|
||||
class CImprovLocomotor;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* The CNavPath class encapsulates a path through space
|
||||
*/
|
||||
class CNavPath
|
||||
{
|
||||
public:
|
||||
CNavPath( void )
|
||||
{
|
||||
m_segmentCount = 0;
|
||||
}
|
||||
|
||||
struct PathSegment
|
||||
{
|
||||
CNavArea *area; ///< the area along the path
|
||||
NavTraverseType how; ///< how to enter this area from the previous one
|
||||
Vector pos; ///< our movement goal position at this point in the path
|
||||
const CNavLadder *ladder; ///< if "how" refers to a ladder, this is it
|
||||
};
|
||||
|
||||
const PathSegment * operator[] ( int i ) const { return (i >= 0 && i < m_segmentCount) ? &m_path[i] : NULL; }
|
||||
const PathSegment *GetSegment( int i ) const { return (i >= 0 && i < m_segmentCount) ? &m_path[i] : NULL; }
|
||||
int GetSegmentCount( void ) const { return m_segmentCount; }
|
||||
const Vector &GetEndpoint( void ) const { return m_path[ m_segmentCount-1 ].pos; }
|
||||
bool IsAtEnd( const Vector &pos ) const; ///< return true if position is at the end of the path
|
||||
|
||||
float GetLength( void ) const; ///< return length of path from start to finish
|
||||
bool GetPointAlongPath( float distAlong, Vector *pointOnPath ) const; ///< return point a given distance along the path - if distance is out of path bounds, point is clamped to start/end
|
||||
|
||||
/// return the node index closest to the given distance along the path without going over - returns (-1) if error
|
||||
int GetSegmentIndexAlongPath( float distAlong ) const;
|
||||
|
||||
bool IsValid( void ) const { return (m_segmentCount > 0); }
|
||||
void Invalidate( void ) { m_segmentCount = 0; }
|
||||
|
||||
void Draw( const Vector &color = Vector( 1.0f, 0.3f, 0 ) ); ///< draw the path for debugging
|
||||
|
||||
/// compute closest point on path to given point
|
||||
bool FindClosestPointOnPath( const Vector *worldPos, int startIndex, int endIndex, Vector *close ) const;
|
||||
|
||||
void Optimize( void );
|
||||
|
||||
/**
|
||||
* Compute shortest path from 'start' to 'goal' via A* algorithm.
|
||||
* If returns true, path was build to the goal position.
|
||||
* If returns false, path may either be invalid (use IsValid() to check), or valid but
|
||||
* doesn't reach all the way to the goal.
|
||||
*/
|
||||
template< typename CostFunctor >
|
||||
bool Compute( const Vector &start, const Vector &goal, CostFunctor &costFunc )
|
||||
{
|
||||
Invalidate();
|
||||
|
||||
CNavArea *startArea = TheNavMesh->GetNearestNavArea( start + Vector( 0.0f, 0.0f, 1.0f ) );
|
||||
if (startArea == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CNavArea *goalArea = TheNavMesh->GetNavArea( goal );
|
||||
|
||||
// if we are already in the goal area, build trivial path
|
||||
if (startArea == goalArea)
|
||||
{
|
||||
BuildTrivialPath( start, goal );
|
||||
return true;
|
||||
}
|
||||
|
||||
// make sure path end position is on the ground
|
||||
Vector pathEndPosition = goal;
|
||||
if (goalArea)
|
||||
{
|
||||
pathEndPosition.z = goalArea->GetZ( pathEndPosition );
|
||||
}
|
||||
else
|
||||
{
|
||||
TheNavMesh->GetGroundHeight( pathEndPosition, &pathEndPosition.z );
|
||||
}
|
||||
|
||||
//
|
||||
// Compute shortest path to goal
|
||||
//
|
||||
CNavArea *closestArea;
|
||||
bool pathResult = NavAreaBuildPath( startArea, goalArea, &goal, costFunc, &closestArea );
|
||||
|
||||
//
|
||||
// Build path by following parent links
|
||||
//
|
||||
|
||||
// get count
|
||||
int count = 0;
|
||||
CNavArea *area;
|
||||
for( area = closestArea; area; area = area->GetParent() )
|
||||
{
|
||||
++count;
|
||||
}
|
||||
|
||||
// save room for endpoint
|
||||
if (count > MAX_PATH_SEGMENTS-1)
|
||||
{
|
||||
count = MAX_PATH_SEGMENTS-1;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
BuildTrivialPath( start, goal );
|
||||
return true;
|
||||
}
|
||||
|
||||
// build path
|
||||
m_segmentCount = count;
|
||||
for( area = closestArea; count && area; area = area->GetParent() )
|
||||
{
|
||||
--count;
|
||||
m_path[ count ].area = area;
|
||||
m_path[ count ].how = area->GetParentHow();
|
||||
}
|
||||
|
||||
// compute path positions
|
||||
if (ComputePathPositions() == false)
|
||||
{
|
||||
//PrintIfWatched( "CNavPath::Compute: Error building path\n" );
|
||||
Invalidate();
|
||||
return false;
|
||||
}
|
||||
|
||||
// append path end position
|
||||
m_path[ m_segmentCount ].area = closestArea;
|
||||
m_path[ m_segmentCount ].pos = pathEndPosition;
|
||||
m_path[ m_segmentCount ].ladder = NULL;
|
||||
m_path[ m_segmentCount ].how = NUM_TRAVERSE_TYPES;
|
||||
++m_segmentCount;
|
||||
|
||||
return pathResult;
|
||||
}
|
||||
|
||||
private:
|
||||
enum { MAX_PATH_SEGMENTS = 256 };
|
||||
PathSegment m_path[ MAX_PATH_SEGMENTS ];
|
||||
int m_segmentCount;
|
||||
|
||||
bool ComputePathPositions( void ); ///< determine actual path positions
|
||||
bool BuildTrivialPath( const Vector &start, const Vector &goal ); ///< utility function for when start and goal are in the same area
|
||||
|
||||
int FindNextOccludedNode( int anchor ); ///< used by Optimize()
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Monitor improv movement and determine if it becomes stuck
|
||||
*/
|
||||
class CStuckMonitor
|
||||
{
|
||||
public:
|
||||
CStuckMonitor( void );
|
||||
|
||||
void Reset( void );
|
||||
void Update( CImprovLocomotor *improv );
|
||||
bool IsStuck( void ) const { return m_isStuck; }
|
||||
|
||||
float GetDuration( void ) const { return (m_isStuck) ? m_stuckTimer.GetElapsedTime() : 0.0f; }
|
||||
|
||||
private:
|
||||
bool m_isStuck; ///< if true, we are stuck
|
||||
Vector m_stuckSpot; ///< the location where we became stuck
|
||||
IntervalTimer m_stuckTimer; ///< how long we have been stuck
|
||||
|
||||
enum { MAX_VEL_SAMPLES = 5 };
|
||||
float m_avgVel[ MAX_VEL_SAMPLES ];
|
||||
int m_avgVelIndex;
|
||||
int m_avgVelCount;
|
||||
Vector m_lastCentroid;
|
||||
float m_lastTime;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* The CNavPathFollower class implements path following behavior
|
||||
*/
|
||||
class CNavPathFollower
|
||||
{
|
||||
public:
|
||||
CNavPathFollower( void );
|
||||
|
||||
void SetImprov( CImprovLocomotor *improv ) { m_improv = improv; }
|
||||
void SetPath( CNavPath *path ) { m_path = path; }
|
||||
|
||||
void Reset( void );
|
||||
|
||||
#define DONT_AVOID_OBSTACLES false
|
||||
void Update( float deltaT, bool avoidObstacles = true ); ///< move improv along path
|
||||
void Debug( bool status ) { m_isDebug = status; } ///< turn debugging on/off
|
||||
|
||||
bool IsStuck( void ) const { return m_stuckMonitor.IsStuck(); } ///< return true if improv is stuck
|
||||
void ResetStuck( void ) { m_stuckMonitor.Reset(); }
|
||||
float GetStuckDuration( void ) const { return m_stuckMonitor.GetDuration(); } ///< return how long we've been stuck
|
||||
|
||||
void FeelerReflexAdjustment( Vector *goalPosition, float height = -1.0f ); ///< adjust goal position if "feelers" are touched
|
||||
|
||||
private:
|
||||
CImprovLocomotor *m_improv; ///< who is doing the path following
|
||||
|
||||
CNavPath *m_path; ///< the path being followed
|
||||
|
||||
int m_segmentIndex; ///< the point on the path the improv is moving towards
|
||||
int m_behindIndex; ///< index of the node on the path just behind us
|
||||
Vector m_goal; ///< last computed follow goal
|
||||
|
||||
bool m_isLadderStarted;
|
||||
|
||||
bool m_isDebug;
|
||||
|
||||
int FindOurPositionOnPath( Vector *close, bool local ) const; ///< return the closest point to our current position on current path
|
||||
int FindPathPoint( float aheadRange, Vector *point, int *prevIndex ); ///< compute a point a fixed distance ahead along our path.
|
||||
|
||||
CStuckMonitor m_stuckMonitor;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // _NAV_PATH_H_
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: dll-agnostic routines (no dll dependencies here)
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Matthew D. Campbell (matt@turtlerockstudios.com), 2003
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include "shared_util.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
static char s_shared_token[ 1500 ];
|
||||
static char s_shared_quote = '\"';
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
char * SharedVarArgs(const char *format, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
const int BufLen = 1024;
|
||||
const int NumBuffers = 4;
|
||||
static char string[NumBuffers][BufLen];
|
||||
static int curstring = 0;
|
||||
|
||||
curstring = ( curstring + 1 ) % NumBuffers;
|
||||
|
||||
va_start (argptr, format);
|
||||
V_vsprintf_safe( string[curstring], format, argptr );
|
||||
va_end (argptr);
|
||||
|
||||
return string[curstring];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
char * BufPrintf(char *buf, int& len, const char *fmt, ...)
|
||||
{
|
||||
if (len <= 0)
|
||||
return NULL;
|
||||
|
||||
va_list argptr;
|
||||
|
||||
va_start(argptr, fmt);
|
||||
_vsnprintf(buf, len, fmt, argptr);
|
||||
buf[ len - 1 ] = 0;
|
||||
va_end(argptr);
|
||||
|
||||
len -= strlen(buf);
|
||||
return buf + strlen(buf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
wchar_t * BufWPrintf(wchar_t *buf, int& len, const wchar_t *fmt, ...)
|
||||
{
|
||||
if (len <= 0)
|
||||
return NULL;
|
||||
|
||||
va_list argptr;
|
||||
|
||||
va_start(argptr, fmt);
|
||||
#ifdef WIN32
|
||||
_vsnwprintf(buf, len, fmt, argptr);
|
||||
#else
|
||||
vswprintf( buf, len, fmt, argptr );
|
||||
#endif
|
||||
buf[ len - 1 ] = 0;
|
||||
va_end(argptr);
|
||||
|
||||
len -= wcslen(buf);
|
||||
return buf + wcslen(buf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
const wchar_t * NumAsWString( int val )
|
||||
{
|
||||
const int BufLen = 16;
|
||||
static wchar_t buf[BufLen];
|
||||
int len = BufLen;
|
||||
BufWPrintf( buf, len, L"%d", val );
|
||||
return buf;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
const char * NumAsString( int val )
|
||||
{
|
||||
const int BufLen = 16;
|
||||
static char buf[BufLen];
|
||||
int len = BufLen;
|
||||
BufPrintf( buf, len, "%d", val );
|
||||
return buf;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns the token parsed by SharedParse()
|
||||
*/
|
||||
char *SharedGetToken( void )
|
||||
{
|
||||
return s_shared_token;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns the token parsed by SharedParse()
|
||||
*/
|
||||
void SharedSetQuoteChar( char c )
|
||||
{
|
||||
s_shared_quote = c;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Parse a token out of a string
|
||||
*/
|
||||
const char *SharedParse( const char *data )
|
||||
{
|
||||
int c;
|
||||
int len;
|
||||
|
||||
len = 0;
|
||||
s_shared_token[0] = 0;
|
||||
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
// skip whitespace
|
||||
skipwhite:
|
||||
while ( (c = *data) <= ' ')
|
||||
{
|
||||
if (c == 0)
|
||||
return NULL; // end of file;
|
||||
data++;
|
||||
}
|
||||
|
||||
// skip // comments
|
||||
if (c=='/' && data[1] == '/')
|
||||
{
|
||||
while (*data && *data != '\n')
|
||||
data++;
|
||||
goto skipwhite;
|
||||
}
|
||||
|
||||
|
||||
// handle quoted strings specially
|
||||
if (c == s_shared_quote)
|
||||
{
|
||||
data++;
|
||||
while (1)
|
||||
{
|
||||
c = *data++;
|
||||
if (c==s_shared_quote || !c)
|
||||
{
|
||||
s_shared_token[len] = 0;
|
||||
return data;
|
||||
}
|
||||
s_shared_token[len] = c;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
// parse single characters
|
||||
if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' )
|
||||
{
|
||||
s_shared_token[len] = c;
|
||||
len++;
|
||||
s_shared_token[len] = 0;
|
||||
return data+1;
|
||||
}
|
||||
|
||||
// parse a regular word
|
||||
do
|
||||
{
|
||||
s_shared_token[len] = c;
|
||||
data++;
|
||||
len++;
|
||||
c = *data;
|
||||
if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' )
|
||||
break;
|
||||
} while (c>32);
|
||||
|
||||
s_shared_token[len] = 0;
|
||||
return data;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns true if additional data is waiting to be processed on this line
|
||||
*/
|
||||
bool SharedTokenWaiting( const char *buffer )
|
||||
{
|
||||
const char *p;
|
||||
|
||||
p = buffer;
|
||||
while ( *p && *p!='\n')
|
||||
{
|
||||
if ( !isspace( *p ) || isalnum( *p ) )
|
||||
return true;
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: dll-agnostic routines (no dll dependencies here)
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
// Author: Matthew D. Campbell (matt@turtlerockstudios.com), 2003
|
||||
|
||||
#ifndef SHARED_UTIL_H
|
||||
#define SHARED_UTIL_H
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns the token parsed by SharedParse()
|
||||
*/
|
||||
char *SharedGetToken( void );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Sets the character used to delimit quoted strings. Default is '\"'. Be sure to set it back when done.
|
||||
*/
|
||||
void SharedSetQuoteChar( char c );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Parse a token out of a string
|
||||
*/
|
||||
const char *SharedParse( const char *data );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns true if additional data is waiting to be processed on this line
|
||||
*/
|
||||
bool SharedTokenWaiting( const char *buffer );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Simple utility function to allocate memory and duplicate a string
|
||||
*/
|
||||
inline char *CloneString( const char *str )
|
||||
{
|
||||
char *cloneStr = new char [ strlen(str)+1 ];
|
||||
strcpy( cloneStr, str );
|
||||
return cloneStr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* snprintf-alike that allows multiple prints into a buffer
|
||||
*/
|
||||
char * BufPrintf(char *buf, int& len, PRINTF_FORMAT_STRING const char *fmt, ...);
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* wide char version of BufPrintf
|
||||
*/
|
||||
wchar_t * BufWPrintf(wchar_t *buf, int& len, PRINTF_FORMAT_STRING const wchar_t *fmt, ...);
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* convenience function that prints an int into a static wchar_t*
|
||||
*/
|
||||
const wchar_t * NumAsWString( int val );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* convenience function that prints an int into a static char*
|
||||
*/
|
||||
const char * NumAsString( int val );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* convenience function that composes a string into a static char*
|
||||
*/
|
||||
char * SharedVarArgs(PRINTF_FORMAT_STRING const char *format, ...);
|
||||
|
||||
#include "tier0/memdbgoff.h"
|
||||
|
||||
#endif // SHARED_UTIL_H
|
||||
@@ -0,0 +1,54 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//-------------------------------------------------------------
|
||||
// File: cs_achievement_constants.h
|
||||
// Desc: Declare contants used by achievements (mostly) in one location for simpler tweaking
|
||||
// Author: Peter Freese <peter@hiddenpath.com>
|
||||
// Date: 2009/03/11
|
||||
// Copyright: © 2009 Hidden Path Entertainment
|
||||
//-------------------------------------------------------------
|
||||
|
||||
#ifndef CS_ACHIEVEMENT_CONSTANTS_H
|
||||
#define CS_ACHIEVEMENT_CONSTANTS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace AchievementConsts
|
||||
{
|
||||
const int DefaultMinOpponentsForAchievement = 5;
|
||||
const int KillingSpree_Kills = 5;
|
||||
const float KillingSpree_WindowTime = 15.0f;
|
||||
const float KillingSpreeEnder_TimeWindow = 5.0f;
|
||||
const int KillEnemyTeam_MinKills = 5;
|
||||
const int LastPlayerAlive_MinPlayersOnTeam = 5;
|
||||
const int KillsWithMultipleGuns_MinWeapons = 5;
|
||||
const float BombDefuseCloseCall_MaxTimeRemaining = 1.0f;
|
||||
const int KillLowDamage_MaxHealthLeft = 5;
|
||||
const int DamageNoKill_MaxHealthLeftOnKill = 5;
|
||||
const float BombDefuseNeededKit_MaxTime = 5.0f;
|
||||
const float FastBombPlant_Time = 25.0f;
|
||||
const int KillEnemiesWhileBlind_Kills = 1;
|
||||
const int KillEnemiesWhileBlindHard_Kills = 2;
|
||||
const int SurviveGrenade_MinDamage = 80;
|
||||
const int KillWhenAtLowHealth_MaxHealth = 1;
|
||||
const int GrenadeMultiKill_MinKills = 3;
|
||||
const int BombMultiKill_MinKills = 5;
|
||||
const float FastRoundWin_Time = 30.0f;
|
||||
const int UnstoppableForce_Kills = 10;
|
||||
const int BreakPropsInRound_Props = 15;
|
||||
const int HeadshotsInRound_Kills = 5;
|
||||
const int BreakWindowsInOfficeRound_Windows = 14;
|
||||
const float FastHostageRescue_Time = 90.0f;
|
||||
const int SurviveManyAttacks_NumberDamagingPlayers = 5;
|
||||
const float KillInAir_MinimumHeight = 100.0f; //100-120 is probably best. Also used for killing while in the air
|
||||
const float KillBombPickup_MaxTime = 3.0f;
|
||||
const int WinRoundsWithoutBuying_Rounds = 10;
|
||||
const int ConcurrentDominations_MinDominations = 3;
|
||||
const int ExtendedDomination_AdditionalKills = 4;
|
||||
const int SameUniform_MinPlayers = 5;
|
||||
const int FriendsSameUniform_MinPlayers = 4;
|
||||
const float KillEnemyNearBomb_MaxDistance = 480.0f;
|
||||
const int GrenadeDamage_MinDamage = 200;
|
||||
}
|
||||
|
||||
#endif // CS_ACHIEVEMENT_CONSTANTS_H
|
||||
@@ -0,0 +1,210 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Shared CS definitions.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CS_ACHIEVEMENTDEFS_H
|
||||
#define CS_ACHIEVEMENTDEFS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// Achievement ID Definitions
|
||||
//=============================================================================
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CSInvalidAchievement = -1,
|
||||
|
||||
// Bomb-related Achievements
|
||||
CSBombAchievementsStart = 1000, // First bomb-related achievement
|
||||
|
||||
CSWinBombPlant,
|
||||
CSWinBombDefuse,
|
||||
CSDefuseAndNeededKit,
|
||||
CSBombDefuseCloseCall,
|
||||
CSKilledDefuser,
|
||||
CSPlantBombWithin25Seconds,
|
||||
CSKillBombPickup,
|
||||
CSBombMultikill,
|
||||
CSGooseChase,
|
||||
CSWinBombPlantAfterRecovery,
|
||||
CSDefuseDefense,
|
||||
CSPlantBombsLow,
|
||||
CSDefuseBombsLow,
|
||||
|
||||
CSBombAchievementsEnd, // Must be after last bomb-related achievement
|
||||
|
||||
|
||||
// Hostage-related Achievements
|
||||
CSHostageAchievementsStart = 2000, // First hostage-related achievement
|
||||
|
||||
CSRescueAllHostagesInARound,
|
||||
CSKilledRescuer,
|
||||
CSFastHostageRescue,
|
||||
CSRescueHostagesLow,
|
||||
CSRescueHostagesMid,
|
||||
|
||||
CSHostageAchievmentEnd, // Must be after last hostage-related achievement
|
||||
|
||||
// General Kill Achievements
|
||||
CSKillAchievementsStart = 3000, // First kill-related achievement
|
||||
|
||||
CSEnemyKillsLow,
|
||||
CSEnemyKillsMed,
|
||||
CSEnemyKillsHigh,
|
||||
CSSurvivedHeadshotDueToHelmet,
|
||||
CSKillEnemyReloading,
|
||||
CSKillingSpree,
|
||||
CSKillsWithMultipleGuns,
|
||||
CSHeadshots,
|
||||
CSAvengeFriend,
|
||||
CSSurviveGrenade,
|
||||
CSDominationsLow,
|
||||
CSDominationsHigh,
|
||||
CSRevengesLow,
|
||||
CSRevengesHigh,
|
||||
CSDominationOverkillsLow,
|
||||
CSDominationOverkillsHigh,
|
||||
CSDominationOverkillsMatch,
|
||||
CSExtendedDomination,
|
||||
CSConcurrentDominations,
|
||||
CSKillEnemyBlinded,
|
||||
CSKillEnemiesWhileBlind,
|
||||
CSKillEnemiesWhileBlindHard,
|
||||
CSKillsEnemyWeapon,
|
||||
CSKillWithEveryWeapon,
|
||||
CSWinKnifeFightsLow,
|
||||
CSWinKnifeFightsHigh,
|
||||
CSKilledDefuserWithGrenade,
|
||||
CSKillSniperWithSniper,
|
||||
CSKillSniperWithKnife,
|
||||
CSHipShot,
|
||||
CSKillSnipers,
|
||||
CSKillWhenAtLowHealth,
|
||||
CSPistolRoundKnifeKill,
|
||||
CSWinDualDuel,
|
||||
CSGrenadeMultikill,
|
||||
CSKillWhileInAir,
|
||||
CSKillEnemyInAir,
|
||||
CSKillerAndEnemyInAir,
|
||||
CSKillEnemyWithFormerGun,
|
||||
CSKillTwoWithOneShot,
|
||||
CSSnipeTwoFromSameSpot,
|
||||
|
||||
CSKillAchievementEnd, // Must be after last kill-related achievement
|
||||
|
||||
// Weapon-related Achievements
|
||||
CSWeaponAchievementsStart = 4000, // First weapon-related achievement
|
||||
|
||||
CSEnemyKillsDeagle,
|
||||
CSEnemyKillsUSP,
|
||||
CSEnemyKillsGlock,
|
||||
CSEnemyKillsP228,
|
||||
CSEnemyKillsElite,
|
||||
CSEnemyKillsFiveSeven,
|
||||
CSEnemyKillsAWP,
|
||||
CSEnemyKillsAK47,
|
||||
CSEnemyKillsM4A1,
|
||||
CSEnemyKillsAUG,
|
||||
CSEnemyKillsSG552,
|
||||
CSEnemyKillsSG550,
|
||||
CSEnemyKillsGALIL,
|
||||
CSEnemyKillsFAMAS,
|
||||
CSEnemyKillsScout,
|
||||
CSEnemyKillsG3SG1,
|
||||
CSEnemyKillsP90,
|
||||
CSEnemyKillsMP5NAVY,
|
||||
CSEnemyKillsTMP,
|
||||
CSEnemyKillsMAC10,
|
||||
CSEnemyKillsUMP45,
|
||||
CSEnemyKillsM3,
|
||||
CSEnemyKillsXM1014,
|
||||
CSEnemyKillsM249,
|
||||
CSEnemyKillsKnife,
|
||||
CSEnemyKillsHEGrenade,
|
||||
CSMetaPistol,
|
||||
CSMetaRifle,
|
||||
CSMetaSMG,
|
||||
CSMetaShotgun,
|
||||
CSMetaWeaponMaster,
|
||||
|
||||
CSWeaponAchievementsEnd, // Must be after last weapon-related achievement
|
||||
|
||||
// General Achievements
|
||||
CSGeneralAchievementsStart = 5000, // First general achievement
|
||||
|
||||
CSWinRoundsLow,
|
||||
CSWinRoundsMed,
|
||||
CSWinRoundsHigh,
|
||||
CSMoneyEarnedLow,
|
||||
CSMoneyEarnedMed,
|
||||
CSMoneyEarnedHigh,
|
||||
CSGiveDamageLow,
|
||||
CSGiveDamageMed,
|
||||
CSGiveDamageHigh,
|
||||
CSPosthumousGrenadeKill,
|
||||
CSKillEnemyTeam,
|
||||
CSLastPlayerAlive,
|
||||
CSKillEnemyLastBullet,
|
||||
CSKillingSpreeEnder,
|
||||
CSDamageNoKill,
|
||||
CSKillLowDamage,
|
||||
CSSurviveManyAttacks,
|
||||
CSLosslessExtermination,
|
||||
CSFlawlessVictory,
|
||||
CSDecalSprays,
|
||||
CSBreakWindows,
|
||||
CSBreakProps,
|
||||
CSUnstoppableForce,
|
||||
CSImmovableObject,
|
||||
CSHeadshotsInRound,
|
||||
CSWinPistolRoundsLow,
|
||||
CSWinPistolRoundsMed,
|
||||
CSWinPistolRoundsHigh,
|
||||
CSFastRoundWin,
|
||||
CSNightvisionDamage,
|
||||
CSSilentWin,
|
||||
CSBloodlessVictory,
|
||||
CSDonateWeapons,
|
||||
CSWinRoundsWithoutBuying,
|
||||
CSSameUniform,
|
||||
CSFriendsSameUniform,
|
||||
CSCauseFriendlyFireWithFlashbang,
|
||||
CSWinClanMatch,
|
||||
CSCollectHolidayGifts,
|
||||
|
||||
CSGeneralAchievementsEnd, // Must be after last general achievement
|
||||
|
||||
CSWinMapAchievementsStart = 6000,
|
||||
|
||||
CSWinMapCS_ASSAULT,
|
||||
CSWinMapCS_COMPOUND,
|
||||
CSWinMapCS_HAVANA,
|
||||
CSWinMapCS_ITALY,
|
||||
CSWinMapCS_MILITIA,
|
||||
CSWinMapCS_OFFICE,
|
||||
CSWinMapDE_AZTEC,
|
||||
CSWinMapDE_CBBLE,
|
||||
CSWinMapDE_CHATEAU,
|
||||
CSWinMapDE_DUST,
|
||||
CSWinMapDE_DUST2,
|
||||
CSWinMapDE_INFERNO,
|
||||
CSWinMapDE_NUKE,
|
||||
CSWinMapDE_PIRANESI,
|
||||
CSWinMapDE_PORT,
|
||||
CSWinMapDE_PRODIGY,
|
||||
CSWinMapDE_TIDES,
|
||||
CSWinMapDE_TRAIN,
|
||||
|
||||
CSWinMapAchievementsEnd //Must be after last map-based achievement
|
||||
|
||||
} eCSAchievementType;
|
||||
|
||||
|
||||
#endif // CS_ACHIEVEMENTDEFS_H
|
||||
@@ -0,0 +1,57 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "cs_ammodef.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCSAmmoDef::AddAmmoCost( char const* name, int cost, int buySize )
|
||||
{
|
||||
int index = Index( name );
|
||||
if ( index < 1 || index >= m_nAmmoIndex )
|
||||
return;
|
||||
|
||||
m_csAmmo[index].buySize = buySize;
|
||||
m_csAmmo[index].cost = cost;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int CCSAmmoDef::GetBuySize( int index ) const
|
||||
{
|
||||
if ( index < 1 || index >= m_nAmmoIndex )
|
||||
return 0;
|
||||
|
||||
return m_csAmmo[index].buySize;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int CCSAmmoDef::GetCost( int index ) const
|
||||
{
|
||||
if ( index < 1 || index >= m_nAmmoIndex )
|
||||
return 0;
|
||||
|
||||
return m_csAmmo[index].cost;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CCSAmmoDef::CCSAmmoDef(void)
|
||||
{
|
||||
memset( m_csAmmo, 0, sizeof( m_csAmmo ) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CCSAmmoDef::~CCSAmmoDef( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -0,0 +1,55 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Holds defintion for game ammo types
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CS_AMMODEF_H
|
||||
#define CS_AMMODEF_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "ammodef.h"
|
||||
#include "cs_blackmarket.h"
|
||||
|
||||
class ConVar;
|
||||
|
||||
struct CSAmmoCost
|
||||
{
|
||||
int buySize;
|
||||
int cost;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// >> CCSAmmoDef
|
||||
//=============================================================================
|
||||
class CCSAmmoDef : public CAmmoDef
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
void AddAmmoCost( char const* name, int cost, int buySize );
|
||||
|
||||
CCSAmmoDef(void);
|
||||
~CCSAmmoDef( void );
|
||||
|
||||
int GetBuySize( int nAmmoIndex ) const;
|
||||
int GetCost( int nAmmoIndex ) const;
|
||||
|
||||
private:
|
||||
CSAmmoCost m_csAmmo[MAX_AMMO_TYPES];
|
||||
};
|
||||
|
||||
|
||||
// Get the global ammodef object. This is usually implemented in each mod's game rules file somewhere,
|
||||
// so the mod can setup custom ammo types.
|
||||
CCSAmmoDef* GetCSAmmoDef();
|
||||
|
||||
|
||||
#endif // CS_AMMODEF_H
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "cs_gamerules.h"
|
||||
#include "cs_blackmarket.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "filesystem.h"
|
||||
#include <KeyValues.h>
|
||||
#include "cs_gamestats.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
extern int g_iRoundCount;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
inline void CBlackMarketElement::NetworkStateChanged()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
inline void CBlackMarketElement::NetworkStateChanged( void *pVar )
|
||||
{
|
||||
}
|
||||
|
||||
blackmarket_items_t blackmarket_items[] =
|
||||
{
|
||||
{ "kevlar", KEVLAR_PRICE },
|
||||
{ "assaultsuit", ASSAULTSUIT_PRICE },
|
||||
{ "nightvision", NVG_PRICE },
|
||||
};
|
||||
|
||||
|
||||
CUtlVector<CBlackMarketElement> g_BlackMarket_WeaponsBought;
|
||||
|
||||
void TrackAutoBuyPurchases( const char *pWeaponName, CCSPlayer *pBuyer )
|
||||
{
|
||||
if ( pBuyer->IsInAutoBuy() == false )
|
||||
return;
|
||||
|
||||
if ( pBuyer->IsInAutoBuy() == true )
|
||||
{
|
||||
if ( Q_stristr( pWeaponName, "m4a1" ) )
|
||||
{
|
||||
g_iAutoBuyM4A1Purchases++;
|
||||
}
|
||||
else if ( Q_stristr( pWeaponName, "ak47" ) )
|
||||
{
|
||||
g_iAutoBuyAK47Purchases++;
|
||||
}
|
||||
else if ( Q_stristr( pWeaponName, "famas" ) )
|
||||
{
|
||||
g_iAutoBuyFamasPurchases++;
|
||||
}
|
||||
else if ( Q_stristr( pWeaponName, "galil" ) )
|
||||
{
|
||||
g_iAutoBuyGalilPurchases++;
|
||||
}
|
||||
else if ( Q_stristr( pWeaponName, "assault" ) )
|
||||
{
|
||||
g_iAutoBuyVestHelmPurchases++;
|
||||
}
|
||||
else if ( Q_stristr( pWeaponName, "kevlar" ) )
|
||||
{
|
||||
g_iAutoBuyVestPurchases++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BlackMarketAddWeapon( const char *pWeaponName, CCSPlayer *pBuyer )
|
||||
{
|
||||
//Ignore bot purchases.
|
||||
if ( pBuyer && pBuyer->IsBot() )
|
||||
return;
|
||||
|
||||
CSWeaponID iWeaponID = AliasToWeaponID( pWeaponName );
|
||||
|
||||
TrackAutoBuyPurchases( pWeaponName, pBuyer );
|
||||
|
||||
if ( g_BlackMarket_WeaponsBought.Count() > 0 )
|
||||
{
|
||||
for ( int i = 0; i < g_BlackMarket_WeaponsBought.Count(); i++ )
|
||||
{
|
||||
if ( g_BlackMarket_WeaponsBought[i].m_iWeaponID == iWeaponID )
|
||||
{
|
||||
g_BlackMarket_WeaponsBought[i].m_iTimesBought++;
|
||||
g_iWeaponPurchases[g_BlackMarket_WeaponsBought[i].m_iWeaponID]++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CBlackMarketElement newweapon;
|
||||
|
||||
newweapon.m_iWeaponID = iWeaponID;
|
||||
newweapon.m_iTimesBought = 1;
|
||||
newweapon.m_iPrice = 0;
|
||||
g_iWeaponPurchases[newweapon.m_iWeaponID] = 1;
|
||||
|
||||
g_BlackMarket_WeaponsBought.AddToTail( newweapon );
|
||||
}
|
||||
|
||||
int GetPistolCount( void )
|
||||
{
|
||||
int iNumPistol = 0;
|
||||
|
||||
for ( int j = 1; j < WEAPON_MAX; j++ )
|
||||
{
|
||||
CCSWeaponInfo *pWeaponInfo = GetWeaponInfo( (CSWeaponID)j );
|
||||
|
||||
if ( pWeaponInfo )
|
||||
{
|
||||
if ( pWeaponInfo->m_WeaponType == WEAPONTYPE_PISTOL )
|
||||
{
|
||||
iNumPistol++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iNumPistol;
|
||||
}
|
||||
|
||||
int GetRifleCount( void )
|
||||
{
|
||||
int iNumRifle = 0;
|
||||
|
||||
for ( int j = 1; j < WEAPON_MAX; j++ )
|
||||
{
|
||||
CCSWeaponInfo *pWeaponInfo = GetWeaponInfo( (CSWeaponID)j );
|
||||
|
||||
if ( pWeaponInfo )
|
||||
{
|
||||
if ( pWeaponInfo->m_WeaponType != WEAPONTYPE_PISTOL )
|
||||
{
|
||||
iNumRifle++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iNumRifle + ARRAYSIZE( blackmarket_items );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,89 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Holds defintion for game ammo types
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CS_BLACKMARKET_H
|
||||
#define CS_BLACKMARKET_H
|
||||
|
||||
#include "cs_weapon_parse.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_cs_player.h"
|
||||
#else
|
||||
#include "cs_player.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
struct blackmarket_items_t
|
||||
{
|
||||
const char *pClassname;
|
||||
int iDefaultPrice;
|
||||
};
|
||||
|
||||
extern blackmarket_items_t blackmarket_items[];
|
||||
|
||||
void BlackMarketAddWeapon( const char *pWeaponName, CCSPlayer *pBuyer );
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
KEVLAR_PRICE = 650,
|
||||
HELMET_PRICE = 350,
|
||||
ASSAULTSUIT_PRICE = 1000,
|
||||
DEFUSEKIT_PRICE = 200,
|
||||
NVG_PRICE = 1250,
|
||||
SHIELD_PRICE = 2200
|
||||
};
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
class CBlackMarketElement
|
||||
{
|
||||
public:
|
||||
|
||||
DECLARE_CLASS_NOBASE( CBlackMarketElement );
|
||||
|
||||
// For CNetworkVars.
|
||||
void NetworkStateChanged();
|
||||
void NetworkStateChanged( void *pVar );
|
||||
|
||||
CBlackMarketElement()
|
||||
{
|
||||
m_iPrice = 0;
|
||||
m_iTimesBought = 0;
|
||||
m_iWeaponID = 0;
|
||||
}
|
||||
|
||||
CNetworkVar( int, m_iPrice );
|
||||
CNetworkVar( int, m_iWeaponID );
|
||||
|
||||
int m_iTimesBought;
|
||||
};
|
||||
|
||||
|
||||
#else
|
||||
|
||||
class C_BlackMarketElement
|
||||
{
|
||||
public:
|
||||
|
||||
// This allows the datatables to access private members.
|
||||
ALLOW_DATATABLES_PRIVATE_ACCESS();
|
||||
|
||||
int m_iWeaponID;
|
||||
int m_iPrice;
|
||||
};
|
||||
|
||||
#define CBlackMarketElement C_BlackMarketElement
|
||||
#endif
|
||||
|
||||
#endif // CS_BLACKMARKET_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,537 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: The TF Game rules object
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CS_GAMERULES_H
|
||||
#define CS_GAMERULES_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "teamplay_gamerules.h"
|
||||
#include "convar.h"
|
||||
#include "cs_shareddefs.h"
|
||||
#include "gamevars_shared.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_cs_player.h"
|
||||
#include "networkstringtable_clientdll.h"
|
||||
#else
|
||||
#include "cs_player.h"
|
||||
#include "funfactmgr_cs.h"
|
||||
#endif
|
||||
|
||||
#include "cs_urlretrieveprices.h"
|
||||
|
||||
//extern ConVar mp_dynamicpricing;
|
||||
|
||||
#define CS_GAMERULES_BLACKMARKET_TABLE_NAME "BlackMarketTable"
|
||||
|
||||
#define WINNER_NONE 0
|
||||
#define WINNER_DRAW 1
|
||||
#define WINNER_TER TEAM_TERRORIST
|
||||
#define WINNER_CT TEAM_CT
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [tj] Forward declaration so we can track bot suicides in the game rules.
|
||||
//=============================================================================
|
||||
|
||||
class CCSBot;
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
extern ConVar mp_startmoney;
|
||||
extern ConVar mp_tkpunish;
|
||||
extern ConVar mp_c4timer;
|
||||
extern ConVar mp_buytime;
|
||||
extern ConVar mp_freezetime;
|
||||
extern ConVar mp_playerid;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
extern ConVar mp_autoteambalance;
|
||||
#endif // !CLIENT_DLL
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CCSGameRules C_CSGameRules
|
||||
#define CCSGameRulesProxy C_CSGameRulesProxy
|
||||
#endif
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
struct playerscore_t
|
||||
{
|
||||
int iPlayerIndex;
|
||||
int iScore;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
class CCSGameRulesProxy : public CGameRulesProxy
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CCSGameRulesProxy, CGameRulesProxy );
|
||||
DECLARE_NETWORKCLASS();
|
||||
};
|
||||
|
||||
|
||||
class CCSGameRules : public CTeamplayRules
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CCSGameRules, CTeamplayRules );
|
||||
|
||||
// Stuff that is shared between client and server.
|
||||
bool IsFreezePeriod();
|
||||
|
||||
virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 );
|
||||
|
||||
float GetMapRemainingTime(); // time till end of map, -1 if timelimit is disabled
|
||||
float GetMapElapsedTime(); // How much time has elapsed since the map started.
|
||||
float GetRoundRemainingTime(); // time till end of round
|
||||
float GetRoundStartTime(); // When this round started.
|
||||
float GetRoundElapsedTime(); // How much time has elapsed since the round started.
|
||||
float GetBuyTimeLength() const;
|
||||
int GetRoundLength() const { return m_iRoundTime; }
|
||||
int SelectDefaultTeam( bool ignoreBots = false );
|
||||
int GetHumanTeam(); // TEAM_UNASSIGNED if no restrictions
|
||||
|
||||
bool IsVIPMap() const;
|
||||
bool IsBombDefuseMap() const;
|
||||
bool IsHostageRescueMap() const;
|
||||
bool IsIntermission() const;
|
||||
bool IsLogoMap() const;
|
||||
bool IsSpawnPointValid( CBaseEntity *pSpot, CBasePlayer *pPlayer );
|
||||
|
||||
bool IsBuyTimeElapsed();
|
||||
|
||||
virtual int DefaultFOV();
|
||||
|
||||
// Get the view vectors for this mod.
|
||||
virtual const CViewVectors* GetViewVectors() const;
|
||||
|
||||
void UploadGameStats( void );
|
||||
int GetStartMoney( void );
|
||||
|
||||
virtual bool IsConnectedUserInfoChangeAllowed( CBasePlayer *pPlayer );
|
||||
|
||||
private:
|
||||
|
||||
float GetExplosionDamageAdjustment(Vector & vecSrc, Vector & vecEnd, 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 *player); // returns a value from 0 to 1 that is the percentage of player visible from src.
|
||||
|
||||
CNetworkVar( bool, m_bFreezePeriod ); // TRUE at beginning of round, set to FALSE when the period expires
|
||||
CNetworkVar( int, m_iRoundTime ); // (From mp_roundtime) - How many seconds long this round is.
|
||||
CNetworkVar( float, m_fRoundStartTime ); // time round has started
|
||||
CNetworkVar( float, m_flGameStartTime );
|
||||
CNetworkVar( int, m_iHostagesRemaining );
|
||||
CNetworkVar( bool, m_bMapHasBombTarget );
|
||||
CNetworkVar( bool, m_bMapHasRescueZone );
|
||||
CNetworkVar( bool, m_bLogoMap ); // If there's an info_player_logo entity, then it's a logo map.
|
||||
CNetworkVar( bool, m_bBlackMarket );
|
||||
|
||||
bool m_bDontUploadStats;
|
||||
|
||||
public:
|
||||
|
||||
bool IsBlackMarket( void ) { return m_bBlackMarket; }
|
||||
int GetNumHostagesRemaining( void ) { return m_iHostagesRemaining; }
|
||||
|
||||
virtual CBaseCombatWeapon *GetNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon );
|
||||
|
||||
virtual const unsigned char *GetEncryptionKey( void ) { return (unsigned char *)"d7NSuLq2"; } // both the client and server need this key
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
DECLARE_CLIENTCLASS_NOBASE(); // This makes datatables able to access our private vars.
|
||||
CCSGameRules();
|
||||
|
||||
#else
|
||||
|
||||
DECLARE_SERVERCLASS_NOBASE(); // This makes datatables able to access our private vars.
|
||||
|
||||
CCSGameRules();
|
||||
virtual ~CCSGameRules();
|
||||
|
||||
void DumpTimers( void ) const; // debugging to help track down a stuck server (rare?)
|
||||
|
||||
CBaseEntity *GetPlayerSpawnSpot( CBasePlayer *pPlayer );
|
||||
|
||||
static void EndRound();
|
||||
|
||||
virtual void PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info );
|
||||
virtual void Think();
|
||||
|
||||
// Called at the end of GameFrame (i.e. after all game logic has run this frame)
|
||||
virtual void EndGameFrame( void );
|
||||
|
||||
// Called when game rules are destroyed by CWorld
|
||||
virtual void LevelShutdown( void );
|
||||
|
||||
virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args );
|
||||
virtual void PlayerSpawn( CBasePlayer *pPlayer );
|
||||
void ShowSpawnPoints();
|
||||
|
||||
virtual void ClientCommandKeyValues( edict_t *pEntity, KeyValues *pKeyValues );
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [menglish] Set up anything for all players that changes based on new players spawning mid-game
|
||||
// Find and return fun fact data
|
||||
// [pfreese] Tracking of "pistol" round
|
||||
//=============================================================================
|
||||
virtual void SpawningLatePlayer(CCSPlayer* pLatePlayer);
|
||||
|
||||
bool IsPistolRound();
|
||||
|
||||
void HostageKilled() { m_hostageWasKilled = true; }
|
||||
void HostageInjured() { m_hostageWasInjured = true; }
|
||||
|
||||
bool WasHostageKilled() { return m_hostageWasKilled; }
|
||||
bool WasHostageInjured() { return m_hostageWasInjured; }
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [tj] So game rules can react to damage taken
|
||||
//=============================================================================
|
||||
|
||||
void PlayerTookDamage(CCSPlayer* player, const CTakeDamageInfo &damageInfo);
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
|
||||
virtual bool PlayTextureSounds( void ) { return true; }
|
||||
// Let the game rules specify if fall death should fade screen to black
|
||||
virtual bool FlPlayerFallDeathDoesScreenFade( CBasePlayer *pl ) { return FALSE; }
|
||||
|
||||
virtual void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore );
|
||||
void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, bool bIgnoreWorld );
|
||||
|
||||
virtual void UpdateClientData( CBasePlayer *pl );
|
||||
|
||||
// Death notices
|
||||
virtual void DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info );
|
||||
|
||||
virtual void InitDefaultAIRelationships( void );
|
||||
|
||||
virtual const char *GetGameDescription( void ) { return "Counter-Strike: Source"; } // this is the game name that gets seen in the server browser
|
||||
virtual const char *AIClassText(int classType);
|
||||
|
||||
virtual bool FShouldSwitchWeapon( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon );
|
||||
|
||||
virtual const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer );
|
||||
|
||||
// Called before entities are created
|
||||
virtual void LevelInitPreEntity();
|
||||
|
||||
// Called after the map has finished loading.
|
||||
virtual void LevelInitPostEntity();
|
||||
|
||||
virtual float FlPlayerFallDamage( CBasePlayer *pPlayer );
|
||||
|
||||
virtual void ClientDisconnected( edict_t *pClient );
|
||||
|
||||
// Recreate all the map entities from the map data (preserving their indices),
|
||||
// then remove everything else except the players.
|
||||
// Also get rid of all world decals.
|
||||
void CleanUpMap();
|
||||
|
||||
void CheckFreezePeriodExpired();
|
||||
void CheckRoundTimeExpired();
|
||||
|
||||
// check if the scenario has been won/lost
|
||||
// return true if the scenario is over, false if the scenario is still in progress
|
||||
bool CheckWinConditions( void );
|
||||
|
||||
void TerminateRound( float tmDelay, int reason );
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [tj] A place to check achievements that occur at the end of the round
|
||||
//=============================================================================
|
||||
void ProcessEndOfRoundAchievements(int iWinnerTeam, int iReason);
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
void RestartRound( void );
|
||||
void BalanceTeams( void );
|
||||
void MoveHumansToHumanTeam( void );
|
||||
bool TeamFull( int team_id );
|
||||
bool TeamStacked( int newTeam_id, int curTeam_id );
|
||||
bool FPlayerCanRespawn( CBasePlayer *pPlayer );
|
||||
void UpdateTeamScores();
|
||||
void CheckMapConditions();
|
||||
void MarkLivingPlayersOnTeamAsNotReceivingMoneyNextRound(int team);
|
||||
|
||||
// Check various conditions to end the map.
|
||||
bool CheckGameOver();
|
||||
bool CheckMaxRounds();
|
||||
bool CheckWinLimit();
|
||||
bool CheckFragLimit();
|
||||
|
||||
void CheckLevelInitialized();
|
||||
void CheckRestartRound();
|
||||
|
||||
|
||||
// Checks if it still needs players to start a round, or if it has enough players to start rounds.
|
||||
// Starts a round and returns true if there are enough players.
|
||||
bool NeededPlayersCheck( bool &bNeededPlayers );
|
||||
|
||||
// Setup counts for m_iNumTerrorist, m_iNumCT, m_iNumSpawnableTerrorist, m_iNumSpawnableCT, etc.
|
||||
void InitializePlayerCounts(
|
||||
int &NumAliveTerrorist,
|
||||
int &NumAliveCT,
|
||||
int &NumDeadTerrorist,
|
||||
int &NumDeadCT
|
||||
);
|
||||
|
||||
// Check to see if the round is over for the various game types. Terminates the round
|
||||
// and returns true if the round should end.
|
||||
bool PrisonRoundEndCheck();
|
||||
bool BombRoundEndCheck( bool bNeededPlayers );
|
||||
bool HostageRescueRoundEndCheck( bool bNeededPlayers );
|
||||
|
||||
// Check to see if the teams exterminated each other. Ends the round and returns true if so.
|
||||
bool TeamExterminationCheck(
|
||||
int NumAliveTerrorist,
|
||||
int NumAliveCT,
|
||||
int NumDeadTerrorist,
|
||||
int NumDeadCT,
|
||||
bool bNeededPlayers
|
||||
);
|
||||
|
||||
void ReadMultiplayCvars();
|
||||
void SwapAllPlayers();
|
||||
|
||||
void BroadcastSound( const char *sound, int team = -1 );
|
||||
|
||||
|
||||
// VIP FUNCTIONS
|
||||
bool VIPRoundEndCheck( bool bNeededPlayers );
|
||||
void PickNextVIP();
|
||||
|
||||
|
||||
// BOMB MAP FUNCTIONS
|
||||
void GiveC4();
|
||||
bool IsThereABomber();
|
||||
bool IsThereABomb();
|
||||
|
||||
// HOSTAGE MAP FUNCTIONS
|
||||
void HostageTouched();
|
||||
|
||||
|
||||
// Sets up g_pPlayerResource.
|
||||
virtual void CreateStandardEntities();
|
||||
virtual const char *GetChatPrefix( bool bTeamOnly, CBasePlayer *pPlayer );
|
||||
virtual const char *GetChatLocation( bool bTeamOnly, CBasePlayer *pPlayer );
|
||||
virtual const char *GetChatFormat( bool bTeamOnly, CBasePlayer *pPlayer );
|
||||
void ClientSettingsChanged( CBasePlayer *pPlayer );
|
||||
|
||||
bool IsCareer( void ) const { return false; } // returns true if this is a CZ "career" game
|
||||
|
||||
virtual bool FAllowNPCs( void );
|
||||
|
||||
protected:
|
||||
virtual void GoToIntermission( void );
|
||||
|
||||
public:
|
||||
|
||||
bool IsFriendlyFireOn();
|
||||
|
||||
virtual void SetAllowWeaponSwitch( bool allow );
|
||||
virtual bool GetAllowWeaponSwitch( void );
|
||||
|
||||
// VARIABLES FOR ALL TYPES OF MAPS
|
||||
bool m_bLevelInitialized;
|
||||
int m_iRoundWinStatus; // 1 == CT's won last round, 2 == Terrorists did, 3 == Draw, no winner
|
||||
int m_iTotalRoundsPlayed;
|
||||
int m_iUnBalancedRounds; // keeps track of the # of consecutive rounds that have gone by where one team outnumbers the other team by more than 2
|
||||
|
||||
// GAME TIMES
|
||||
int m_iFreezeTime; // (From mp_freezetime) - How many seconds long the intro round (when players are frozen) is.
|
||||
float m_flRestartRoundTime; // the global time when the round is supposed to end, if this is not 0
|
||||
|
||||
int m_iNumTerrorist; // The number of terrorists on the team (this is generated at the end of a round)
|
||||
int m_iNumCT; // The number of CTs on the team (this is generated at the end of a round)
|
||||
int m_iNumSpawnableTerrorist;
|
||||
int m_iNumSpawnableCT;
|
||||
|
||||
bool m_bFirstConnected;
|
||||
bool m_bCompleteReset; // Set to TRUE to have the scores reset next time round restarts
|
||||
|
||||
int m_iAccountTerrorist;
|
||||
int m_iAccountCT;
|
||||
|
||||
short m_iNumCTWins;
|
||||
short m_iNumTerroristWins;
|
||||
|
||||
int m_iNumConsecutiveCTLoses; //SupraFiend: the number of rounds the CTs have lost in a row.
|
||||
int m_iNumConsecutiveTerroristLoses;//SupraFiend: the number of rounds the Terrorists have lost in a row.
|
||||
|
||||
int m_iSpawnPointCount_Terrorist; // Number of Terrorist spawn points
|
||||
int m_iSpawnPointCount_CT; // Number of CT spawn points
|
||||
|
||||
bool m_bTCantBuy; // Who can and can't buy.
|
||||
bool m_bCTCantBuy;
|
||||
bool m_bMapHasBuyZone;
|
||||
|
||||
int m_iLoserBonus; // SupraFiend: the amount of money the losing team gets. This scales up as they lose more rounds in a row
|
||||
float m_tmNextPeriodicThink;
|
||||
|
||||
|
||||
// HOSTAGE RESCUE VARIABLES
|
||||
int m_iHostagesRescued;
|
||||
int m_iHostagesTouched;
|
||||
float m_flNextHostageAnnouncement;
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN
|
||||
//=============================================================================
|
||||
|
||||
// [tj] Accessor for weapons donation ability
|
||||
bool GetCanDonateWeapon() { return m_bCanDonateWeapons; }
|
||||
|
||||
// [tj] flawless and lossless round related flags
|
||||
bool m_bNoTerroristsKilled;
|
||||
bool m_bNoCTsKilled;
|
||||
bool m_bNoTerroristsDamaged;
|
||||
bool m_bNoCTsDamaged;
|
||||
|
||||
// [tj] Find out if dropped weapons count as donations
|
||||
bool m_bCanDonateWeapons;
|
||||
|
||||
// [tj] Keep track of first kill
|
||||
CHandle<CCSPlayer> m_pFirstKill;
|
||||
float m_firstKillTime;
|
||||
|
||||
// [menglish] Keep track of first blood
|
||||
CHandle<CCSPlayer> m_pFirstBlood;
|
||||
float m_firstBloodTime;
|
||||
|
||||
|
||||
// [dwenger] Rescue-related achievement values
|
||||
CHandle<CCSPlayer> m_pLastRescuer;
|
||||
int m_iNumRescuers;
|
||||
|
||||
bool m_hostageWasInjured;
|
||||
bool m_hostageWasKilled;
|
||||
|
||||
// [menglish] Fun Fact Manager
|
||||
CCSFunFactMgr *m_pFunFactManager;
|
||||
|
||||
// [tj] To avoid rewriting the same piece of code, we can get all the information
|
||||
// we want from one call that fills in an array of structures.
|
||||
struct TeamPlayerCounts
|
||||
{
|
||||
int totalPlayers;
|
||||
int totalAlivePlayers;
|
||||
int totalDeadPlayers; //sum of killedPlayers + suicidedPlayers + unenteredPlayers
|
||||
int killedPlayers;
|
||||
int suicidedPlayers;
|
||||
int unenteredPlayers;
|
||||
};
|
||||
|
||||
void GetPlayerCounts(TeamPlayerCounts teamCounts[TEAM_MAXCOUNT]);
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
|
||||
// PRISON ESCAPE VARIABLES
|
||||
int m_iHaveEscaped;
|
||||
bool m_bMapHasEscapeZone;
|
||||
int m_iNumEscapers;
|
||||
int m_iNumEscapeRounds; // keeps track of the # of consecutive rounds of escape played.. Teams will be swapped after 8 rounds
|
||||
|
||||
|
||||
// VIP VARIABLES
|
||||
int m_iMapHasVIPSafetyZone; // 0 = uninitialized; 1 = has VIP safety zone; 2 = DOES not have VIP safetyzone
|
||||
CHandle<CCSPlayer> m_pVIP;
|
||||
int m_iConsecutiveVIP;
|
||||
|
||||
|
||||
// BOMB MAP VARIABLES
|
||||
bool m_bTargetBombed; // whether or not the bomb has been bombed
|
||||
bool m_bBombDefused; // whether or not the bomb has been defused
|
||||
bool m_bMapHasBombZone;
|
||||
bool m_bBombDropped;
|
||||
bool m_bBombPlanted;
|
||||
EHANDLE m_pLastBombGuy;
|
||||
|
||||
private:
|
||||
|
||||
// Don't allow switching weapons while gaining new technologies
|
||||
bool m_bAllowWeaponSwitch;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
|
||||
void AddPricesToTable( weeklyprice_t prices );
|
||||
virtual void CreateCustomNetworkStringTables( void );
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef GAME_DLL
|
||||
public:
|
||||
virtual void GetTaggedConVarList( KeyValues *pCvarTagList );
|
||||
#endif
|
||||
|
||||
public:
|
||||
const weeklyprice_t *GetBlackMarketPriceList( void );
|
||||
|
||||
int GetBlackMarketPriceForWeapon( int iWeaponID );
|
||||
int GetBlackMarketPreviousPriceForWeapon( int iWeaponID );
|
||||
|
||||
void SetBlackMarketPrices( bool bSetDefaults );
|
||||
|
||||
// Black market
|
||||
INetworkStringTable *m_StringTableBlackMarket;
|
||||
const weeklyprice_t *m_pPrices;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Gets us at the team fortress game rules
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline CCSGameRules* CSGameRules()
|
||||
{
|
||||
return static_cast<CCSGameRules*>(g_pGameRules);
|
||||
}
|
||||
|
||||
#define IGNORE_SPECTATORS true
|
||||
int UTIL_HumansInGame( bool ignoreSpectators = false );
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Useful utility functions
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#else
|
||||
|
||||
class CTFTeam;
|
||||
CTFTeam *GetOpposingTeam( CTeam *pTeam );
|
||||
bool EntityPlacementTest( CBaseEntity *pMainEnt, const Vector &vOrigin, Vector &outPos, bool bDropToGround );
|
||||
|
||||
#endif
|
||||
|
||||
#endif // TF_GAMERULES_H
|
||||
@@ -0,0 +1,410 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "fmtstr.h"
|
||||
#ifdef GAME_DLL
|
||||
#include "gamestats.h"
|
||||
#endif
|
||||
#include "cs_gamestats_shared.h"
|
||||
|
||||
ConVar sv_noroundstats( "sv_noroundstats", "1", FCVAR_REPLICATED, "A temporary variable that can be used for disabling upload of round stats." );
|
||||
|
||||
const MapName_MapStatId MapName_StatId_Table[] =
|
||||
{
|
||||
{"cs_assault", CSSTAT_MAP_WINS_CS_ASSAULT, CSSTAT_MAP_ROUNDS_CS_ASSAULT },
|
||||
{"cs_compound", CSSTAT_MAP_WINS_CS_COMPOUND, CSSTAT_MAP_ROUNDS_CS_COMPOUND },
|
||||
{"cs_havana", CSSTAT_MAP_WINS_CS_HAVANA, CSSTAT_MAP_ROUNDS_CS_HAVANA },
|
||||
{"cs_italy", CSSTAT_MAP_WINS_CS_ITALY, CSSTAT_MAP_ROUNDS_CS_ITALY },
|
||||
{"cs_militia", CSSTAT_MAP_WINS_CS_MILITIA, CSSTAT_MAP_ROUNDS_CS_MILITIA },
|
||||
{"cs_office", CSSTAT_MAP_WINS_CS_OFFICE, CSSTAT_MAP_ROUNDS_CS_OFFICE },
|
||||
{"de_aztec", CSSTAT_MAP_WINS_DE_AZTEC, CSSTAT_MAP_ROUNDS_DE_AZTEC },
|
||||
{"de_cbble", CSSTAT_MAP_WINS_DE_CBBLE, CSSTAT_MAP_ROUNDS_DE_CBBLE },
|
||||
{"de_chateau", CSSTAT_MAP_WINS_DE_CHATEAU, CSSTAT_MAP_ROUNDS_DE_CHATEAU },
|
||||
{"de_dust2", CSSTAT_MAP_WINS_DE_DUST2, CSSTAT_MAP_ROUNDS_DE_DUST2 },
|
||||
{"de_dust", CSSTAT_MAP_WINS_DE_DUST, CSSTAT_MAP_ROUNDS_DE_DUST },
|
||||
{"de_inferno", CSSTAT_MAP_WINS_DE_INFERNO, CSSTAT_MAP_ROUNDS_DE_INFERNO },
|
||||
{"de_nuke", CSSTAT_MAP_WINS_DE_NUKE, CSSTAT_MAP_ROUNDS_DE_NUKE },
|
||||
{"de_piranesi", CSSTAT_MAP_WINS_DE_PIRANESI, CSSTAT_MAP_ROUNDS_DE_PIRANESI },
|
||||
{"de_port", CSSTAT_MAP_WINS_DE_PORT, CSSTAT_MAP_ROUNDS_DE_PORT },
|
||||
{"de_prodigy", CSSTAT_MAP_WINS_DE_PRODIGY, CSSTAT_MAP_ROUNDS_DE_PRODIGY },
|
||||
{"de_tides", CSSTAT_MAP_WINS_DE_TIDES, CSSTAT_MAP_ROUNDS_DE_TIDES },
|
||||
{"de_train", CSSTAT_MAP_WINS_DE_TRAIN, CSSTAT_MAP_ROUNDS_DE_TRAIN },
|
||||
{"", CSSTAT_UNDEFINED, CSSTAT_UNDEFINED },
|
||||
};
|
||||
|
||||
const WeaponName_StatId WeaponName_StatId_Table[] =
|
||||
{
|
||||
{ WEAPON_DEAGLE, CSSTAT_KILLS_DEAGLE, CSSTAT_SHOTS_DEAGLE, CSSTAT_HITS_DEAGLE, CSSTAT_DAMAGE_DEAGLE },
|
||||
{ WEAPON_USP, CSSTAT_KILLS_USP, CSSTAT_SHOTS_USP, CSSTAT_HITS_USP, CSSTAT_DAMAGE_USP },
|
||||
{ WEAPON_GLOCK, CSSTAT_KILLS_GLOCK, CSSTAT_SHOTS_GLOCK, CSSTAT_HITS_GLOCK, CSSTAT_DAMAGE_GLOCK },
|
||||
{ WEAPON_P228, CSSTAT_KILLS_P228, CSSTAT_SHOTS_P228, CSSTAT_HITS_P228, CSSTAT_DAMAGE_P228 },
|
||||
{ WEAPON_ELITE, CSSTAT_KILLS_ELITE, CSSTAT_SHOTS_ELITE, CSSTAT_HITS_ELITE, CSSTAT_DAMAGE_ELITE },
|
||||
{ WEAPON_FIVESEVEN, CSSTAT_KILLS_FIVESEVEN, CSSTAT_SHOTS_FIVESEVEN, CSSTAT_HITS_FIVESEVEN, CSSTAT_DAMAGE_FIVESEVEN },
|
||||
{ WEAPON_AWP, CSSTAT_KILLS_AWP, CSSTAT_SHOTS_AWP, CSSTAT_HITS_AWP, CSSTAT_DAMAGE_AWP },
|
||||
{ WEAPON_AK47, CSSTAT_KILLS_AK47, CSSTAT_SHOTS_AK47, CSSTAT_HITS_AK47, CSSTAT_DAMAGE_AK47 },
|
||||
{ WEAPON_M4A1, CSSTAT_KILLS_M4A1, CSSTAT_SHOTS_M4A1, CSSTAT_HITS_M4A1, CSSTAT_DAMAGE_M4A1 },
|
||||
{ WEAPON_AUG, CSSTAT_KILLS_AUG, CSSTAT_SHOTS_AUG, CSSTAT_HITS_AUG, CSSTAT_DAMAGE_AUG },
|
||||
{ WEAPON_SG552, CSSTAT_KILLS_SG552, CSSTAT_SHOTS_SG552, CSSTAT_HITS_SG552, CSSTAT_DAMAGE_SG552 },
|
||||
{ WEAPON_SG550, CSSTAT_KILLS_SG550, CSSTAT_SHOTS_SG550, CSSTAT_HITS_SG550, CSSTAT_DAMAGE_SG550 },
|
||||
{ WEAPON_GALIL, CSSTAT_KILLS_GALIL, CSSTAT_SHOTS_GALIL, CSSTAT_HITS_GALIL, CSSTAT_DAMAGE_GALIL },
|
||||
{ WEAPON_FAMAS, CSSTAT_KILLS_FAMAS, CSSTAT_SHOTS_FAMAS, CSSTAT_HITS_FAMAS, CSSTAT_DAMAGE_FAMAS },
|
||||
{ WEAPON_SCOUT, CSSTAT_KILLS_SCOUT, CSSTAT_SHOTS_SCOUT, CSSTAT_HITS_SCOUT, CSSTAT_DAMAGE_SCOUT },
|
||||
{ WEAPON_G3SG1, CSSTAT_KILLS_G3SG1, CSSTAT_SHOTS_G3SG1, CSSTAT_HITS_G3SG1, CSSTAT_DAMAGE_G3SG1 },
|
||||
{ WEAPON_P90, CSSTAT_KILLS_P90, CSSTAT_SHOTS_P90, CSSTAT_HITS_P90, CSSTAT_DAMAGE_P90 },
|
||||
{ WEAPON_MP5NAVY, CSSTAT_KILLS_MP5NAVY, CSSTAT_SHOTS_MP5NAVY, CSSTAT_HITS_MP5NAVY, CSSTAT_DAMAGE_MP5NAVY },
|
||||
{ WEAPON_TMP, CSSTAT_KILLS_TMP, CSSTAT_SHOTS_TMP, CSSTAT_HITS_TMP, CSSTAT_DAMAGE_TMP },
|
||||
{ WEAPON_MAC10, CSSTAT_KILLS_MAC10, CSSTAT_SHOTS_MAC10, CSSTAT_HITS_MAC10, CSSTAT_DAMAGE_MAC10 },
|
||||
{ WEAPON_UMP45, CSSTAT_KILLS_UMP45, CSSTAT_SHOTS_UMP45, CSSTAT_HITS_UMP45, CSSTAT_DAMAGE_UMP45 },
|
||||
{ WEAPON_M3, CSSTAT_KILLS_M3, CSSTAT_SHOTS_M3, CSSTAT_HITS_M3, CSSTAT_DAMAGE_M3 },
|
||||
{ WEAPON_XM1014, CSSTAT_KILLS_XM1014, CSSTAT_SHOTS_XM1014, CSSTAT_HITS_XM1014, CSSTAT_DAMAGE_XM1014 },
|
||||
{ WEAPON_M249, CSSTAT_KILLS_M249, CSSTAT_SHOTS_M249, CSSTAT_HITS_M249, CSSTAT_DAMAGE_M249 },
|
||||
{ WEAPON_KNIFE, CSSTAT_KILLS_KNIFE, CSSTAT_SHOTS_KNIFE, CSSTAT_HITS_KNIFE, CSSTAT_DAMAGE_KNIFE },
|
||||
{ WEAPON_HEGRENADE, CSSTAT_KILLS_HEGRENADE, CSSTAT_SHOTS_HEGRENADE, CSSTAT_HITS_HEGRENADE, CSSTAT_DAMAGE_HEGRENADE },
|
||||
|
||||
{ WEAPON_NONE, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED }, // This is a sentinel value so we can loop through all the stats
|
||||
};
|
||||
|
||||
CSStatProperty CSStatProperty_Table[] =
|
||||
{
|
||||
// StatId Steam Name Localization Token Client Update Priority
|
||||
{ CSSTAT_SHOTS_HIT, "i_NumShotsHit", "#GAMEUI_Stat_NumHits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_FIRED, "i_NumShotsFired", "#GAMEUI_Stat_NumShots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_KILLS, "i_Number_Of_Kills", "#GAMEUI_Stat_NumKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_DEATHS, "i_Number_Of_Deaths", "#GAMEUI_Stat_NumDeaths", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_DAMAGE, "i_Damage_Done", "#GAMEUI_Stat_DamageDone", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_NUM_BOMBS_PLANTED, "i_Number_Of_PlantedBombs", "#GAMEUI_Stat_NumPlantedBombs", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_NUM_BOMBS_DEFUSED, "i_Number_Of_DefusedBombs", "#GAMEUI_Stat_NumDefusedBombs", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_PLAYTIME, "i_Time_Played", "#GAMEUI_Stat_TimePlayed", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_ROUNDS_WON, "total_wins", "#GAMEUI_Stat_TotalWins", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_T_ROUNDS_WON, NULL, NULL, CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_CT_ROUNDS_WON, NULL, NULL, CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_ROUNDS_PLAYED, "i_Total_Rounds", "#GAMEUI_Stat_TotalRounds", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_PISTOLROUNDS_WON, "total_wins_pistolround", "#GAMEUI_Stat_PistolRoundWins", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MONEY_EARNED, "i_Money_Earned", "#GAMEUI_Stat_MoneyEarned", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_OBJECTIVES_COMPLETED, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_BOMBS_DEFUSED_WITHKIT, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
|
||||
{ CSSTAT_KILLS_DEAGLE, "total_kills_deagle", "#GAMEUI_Stat_DeagleKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_USP, "total_kills_usp", "#GAMEUI_Stat_USPKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_GLOCK, "total_kills_glock", "#GAMEUI_Stat_GlockKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_P228, "total_kills_p228", "#GAMEUI_Stat_P228Kills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_ELITE, "total_kills_elite", "#GAMEUI_Stat_EliteKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_FIVESEVEN, "total_kills_fiveseven", "#GAMEUI_Stat_FiveSevenKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_AWP, "total_kills_awp", "#GAMEUI_Stat_AWPKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_AK47, "total_kills_ak47", "#GAMEUI_Stat_AK47Kills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_M4A1, "total_kills_m4a1", "#GAMEUI_Stat_M4A1Kills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_AUG, "total_kills_aug", "#GAMEUI_Stat_AUGKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_SG552, "total_kills_sg552", "#GAMEUI_Stat_SG552Kills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_SG550, "total_kills_sg550", "#GAMEUI_Stat_SG550Kills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_GALIL, "total_kills_galil", "#GAMEUI_Stat_GALILKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_FAMAS, "total_kills_famas", "#GAMEUI_Stat_FAMASKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_SCOUT, "total_kills_scout", "#GAMEUI_Stat_ScoutKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_G3SG1, "total_kills_g3sg1", "#GAMEUI_Stat_G3SG1Kills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_P90, "total_kills_p90", "#GAMEUI_Stat_P90Kills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_MP5NAVY, "total_kills_mp5navy", "#GAMEUI_Stat_MP5NavyKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_TMP, "total_kills_tmp", "#GAMEUI_Stat_TMPKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_MAC10, "total_kills_mac10", "#GAMEUI_Stat_MAC10Kills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_UMP45, "total_kills_ump45", "#GAMEUI_Stat_UMP45Kills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_M3, "total_kills_m3", "#GAMEUI_Stat_M3Kills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_XM1014, "total_kills_xm1014", "#GAMEUI_Stat_XM1014Kills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_M249, "total_kills_m249", "#GAMEUI_Stat_M249Kills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_KNIFE, "total_kills_knife", "#GAMEUI_Stat_KnifeKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_HEGRENADE, "total_kills_hegrenade", "#GAMEUI_Stat_HEGrenadeKills", CSSTAT_PRIORITY_HIGH, },
|
||||
|
||||
{ CSSTAT_SHOTS_DEAGLE, "total_shots_deagle", "#GAMEUI_Stat_DeagleShots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_USP, "total_shots_usp", "#GAMEUI_Stat_USPShots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_GLOCK, "total_shots_glock", "#GAMEUI_Stat_GlockShots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_P228, "total_shots_p228", "#GAMEUI_Stat_P228Shots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_ELITE, "total_shots_elite", "#GAMEUI_Stat_EliteShots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_FIVESEVEN, "total_shots_fiveseven", "#GAMEUI_Stat_FiveSevenShots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_AWP, "total_shots_awp", "#GAMEUI_Stat_AWPShots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_AK47, "total_shots_ak47", "#GAMEUI_Stat_AK47Shots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_M4A1, "total_shots_m4a1", "#GAMEUI_Stat_M4A1Shots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_AUG, "total_shots_aug", "#GAMEUI_Stat_AUGShots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_SG552, "total_shots_sg552", "#GAMEUI_Stat_SG552Shots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_SG550, "total_shots_sg550", "#GAMEUI_Stat_SG550Shots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_GALIL, "total_shots_galil", "#GAMEUI_Stat_GALILShots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_FAMAS, "total_shots_famas", "#GAMEUI_Stat_FAMASShots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_SCOUT, "total_shots_scout", "#GAMEUI_Stat_ScoutShots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_G3SG1, "total_shots_g3sg1", "#GAMEUI_Stat_G3SG1Shots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_P90, "total_shots_p90", "#GAMEUI_Stat_P90Shots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_MP5NAVY, "total_shots_mp5navy", "#GAMEUI_Stat_MP5NavyShots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_TMP, "total_shots_tmp", "#GAMEUI_Stat_TMPShots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_MAC10, "total_shots_mac10", "#GAMEUI_Stat_MAC10Shots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_UMP45, "total_shots_ump45", "#GAMEUI_Stat_UMP45Shots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_M3, "total_shots_m3", "#GAMEUI_Stat_M3Shots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_XM1014, "total_shots_xm1014", "#GAMEUI_Stat_XM1014Shots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_M249, "total_shots_m249", "#GAMEUI_Stat_M249Shots", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_SHOTS_KNIFE, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_SHOTS_HEGRENADE, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
|
||||
{ CSSTAT_HITS_DEAGLE, "total_hits_deagle", "#GAMEUI_Stat_DeagleHits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_USP, "total_hits_usp", "#GAMEUI_Stat_USPHits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_GLOCK, "total_hits_glock", "#GAMEUI_Stat_GlockHits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_P228, "total_hits_p228", "#GAMEUI_Stat_P228Hits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_ELITE, "total_hits_elite", "#GAMEUI_Stat_EliteHits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_FIVESEVEN, "total_hits_fiveseven", "#GAMEUI_Stat_FiveSevenHits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_AWP, "total_hits_awp", "#GAMEUI_Stat_AWPHits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_AK47, "total_hits_ak47", "#GAMEUI_Stat_AK47Hits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_M4A1, "total_hits_m4a1", "#GAMEUI_Stat_M4A1Hits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_AUG, "total_hits_aug", "#GAMEUI_Stat_AUGHits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_SG552, "total_hits_sg552", "#GAMEUI_Stat_SG552Hits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_SG550, "total_hits_sg550", "#GAMEUI_Stat_SG550Hits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_GALIL, "total_hits_galil", "#GAMEUI_Stat_GALILHits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_FAMAS, "total_hits_famas", "#GAMEUI_Stat_FAMASHits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_SCOUT, "total_hits_scout", "#GAMEUI_Stat_ScoutHits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_G3SG1, "total_hits_g3sg1", "#GAMEUI_Stat_G3SG1Hits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_P90, "total_hits_p90", "#GAMEUI_Stat_P90Hits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_MP5NAVY, "total_hits_mp5navy", "#GAMEUI_Stat_MP5NavyHits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_TMP, "total_hits_tmp", "#GAMEUI_Stat_TMPHits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_MAC10, "total_hits_mac10", "#GAMEUI_Stat_MAC10Hits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_UMP45, "total_hits_ump45", "#GAMEUI_Stat_UMP45Hits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_M3, "total_hits_m3", "#GAMEUI_Stat_M3Hits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_XM1014, "total_hits_xm1014", "#GAMEUI_Stat_XM1014Hits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_M249, "total_hits_m249", "#GAMEUI_Stat_M249Hits", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_HITS_KNIFE, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_HITS_HEGRENADE, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
|
||||
{ CSSTAT_DAMAGE_DEAGLE, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_USP, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_GLOCK, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_P228, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_ELITE, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_FIVESEVEN, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_AWP, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_AK47, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_M4A1, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_AUG, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_SG552, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_SG550, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_GALIL, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_FAMAS, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_SCOUT, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_G3SG1, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_P90, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_MP5NAVY, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_TMP, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_MAC10, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_UMP45, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_M3, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_XM1014, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_M249, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_KNIFE, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_DAMAGE_HEGRENADE, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
|
||||
{ CSSTAT_KILLS_HEADSHOT, "total_kills_headshot", "#GAMEUI_Stat_HeadshotKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_ENEMY_BLINDED, "total_kills_enemy_blinded", "#GAMEUI_Stat_BlindedEnemyKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_WHILE_BLINDED, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_KILLS_WITH_LAST_ROUND, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_KILLS_ENEMY_WEAPON, "total_kills_enemy_weapon", "#GAMEUI_Stat_EnemyWeaponKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_KNIFE_FIGHT, "total_kills_knife_fight", "#GAMEUI_Stat_KnifeFightKills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_KILLS_WHILE_DEFENDING_BOMB, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
|
||||
{ CSSTAT_DECAL_SPRAYS, "total_decal_sprays", "#GAMEUI_Stat_DecalSprays", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_TOTAL_JUMPS, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_NIGHTVISION_DAMAGE, "total_nightvision_damage", "#GAMEUI_Stat_NightvisionDamage", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_KILLS_WHILE_LAST_PLAYER_ALIVE, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_KILLS_ENEMY_WOUNDED, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_FALL_DAMAGE, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
|
||||
{ CSSTAT_NUM_HOSTAGES_RESCUED, "i_Number_Of_RescuedHostages", "#GAMEUI_Stat_NumRescuedHostages", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_NUM_BROKEN_WINDOWS, "i_Number_Of_BrokenWindows", "#GAMEUI_Stat_NumBrokenWindows", CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_PROPSBROKEN_ALL, NULL, NULL, CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_PROPSBROKEN_MELON, NULL, NULL, CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_PROPSBROKEN_OFFICEELECTRONICS, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_PROPSBROKEN_OFFICERADIO, NULL, NULL, CSSTAT_PRIORITY_LOW, },
|
||||
{ CSSTAT_PROPSBROKEN_OFFICEJUNK, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_PROPSBROKEN_ITALY_MELON, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
|
||||
{ CSSTAT_KILLS_AGAINST_ZOOMED_SNIPER, "total_kills_against_zoomed_sniper","#GAMEUI_Stat_ZoomedSniperKills", CSSTAT_PRIORITY_HIGH, },
|
||||
|
||||
{ CSSTAT_WEAPONS_DONATED, "total_weapons_donated", "#GAMEUI_Stat_WeaponsDonated", CSSTAT_PRIORITY_HIGH, },
|
||||
|
||||
{ CSSTAT_ITEMS_PURCHASED, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_MONEY_SPENT, NULL, NULL, CSSTAT_PRIORITY_LOW, },
|
||||
|
||||
{ CSSTAT_DOMINATIONS, "total_dominations", "#GAMEUI_Stat_Dominations", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_DOMINATION_OVERKILLS, "total_domination_overkills", "#GAMEUI_Stat_DominationOverkills", CSSTAT_PRIORITY_HIGH, },
|
||||
{ CSSTAT_REVENGES, "total_revenges", "#GAMEUI_Stat_Revenges", CSSTAT_PRIORITY_HIGH, },
|
||||
|
||||
{ CSSTAT_MVPS, "total_mvps", "#GAMEUI_Stat_MVPs", CSSTAT_PRIORITY_HIGH, },
|
||||
|
||||
{ CSSTAT_GRENADE_DAMAGE, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_GRENADE_POSTHUMOUSKILLS, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSSTAT_GRENADES_THROWN, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
{ CSTAT_ITEMS_DROPPED_VALUE, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
|
||||
|
||||
{ CSSTAT_MAP_WINS_CS_ASSAULT, "total_wins_map_cs_assault", "#GAMEUI_Stat_WinsMapCSAssault", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_CS_COMPOUND, "total_wins_map_cs_compound", "#GAMEUI_Stat_WinsMapCSCompound", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_CS_HAVANA, "total_wins_map_cs_havana", "#GAMEUI_Stat_WinsMapCSHavana", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_CS_ITALY, "total_wins_map_cs_italy", "#GAMEUI_Stat_WinsMapCSItaly", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_CS_MILITIA, "total_wins_map_cs_militia", "#GAMEUI_Stat_WinsMapCSMilitia", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_CS_OFFICE, "total_wins_map_cs_office", "#GAMEUI_Stat_WinsMapCSOffice", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_DE_AZTEC, "total_wins_map_de_aztec", "#GAMEUI_Stat_WinsMapDEAztec", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_DE_CBBLE, "total_wins_map_de_cbble", "#GAMEUI_Stat_WinsMapDECbble", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_DE_CHATEAU, "total_wins_map_de_chateau", "#GAMEUI_Stat_WinsMapDEChateau", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_DE_DUST2, "total_wins_map_de_dust2", "#GAMEUI_Stat_WinsMapDEDust2", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_DE_DUST, "total_wins_map_de_dust", "#GAMEUI_Stat_WinsMapDEDust", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_DE_INFERNO, "total_wins_map_de_inferno", "#GAMEUI_Stat_WinsMapDEInferno", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_DE_NUKE, "total_wins_map_de_nuke", "#GAMEUI_Stat_WinsMapDENuke", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_DE_PIRANESI, "total_wins_map_de_piranesi", "#GAMEUI_Stat_WinsMapDEPiranesi", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_DE_PORT, "total_wins_map_de_port", "#GAMEUI_Stat_WinsMapDEPort", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_DE_PRODIGY, "total_wins_map_de_prodigy", "#GAMEUI_Stat_WinsMapDEProdigy", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_DE_TIDES, "total_wins_map_de_tides", "#GAMEUI_Stat_WinsMapDETides", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_WINS_DE_TRAIN, "total_wins_map_de_train", "#GAMEUI_Stat_WinsMapDETrain", CSSTAT_PRIORITY_ENDROUND, },
|
||||
|
||||
{ CSSTAT_MAP_ROUNDS_CS_ASSAULT, "total_rounds_map_cs_assault", "#GAMEUI_Stat_RoundsMapCSAssault", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_CS_COMPOUND, "total_rounds_map_cs_compound", "#GAMEUI_Stat_RoundsMapCSCompound", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_CS_HAVANA, "total_rounds_map_cs_havana", "#GAMEUI_Stat_RoundsMapCSHavana", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_CS_ITALY, "total_rounds_map_cs_italy", "#GAMEUI_Stat_RoundsMapCSItaly", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_CS_MILITIA, "total_rounds_map_cs_militia", "#GAMEUI_Stat_RoundsMapCSMilitia", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_CS_OFFICE, "total_rounds_map_cs_office", "#GAMEUI_Stat_RoundsMapCSOffice", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_DE_AZTEC, "total_rounds_map_de_aztec", "#GAMEUI_Stat_RoundsMapDEAztec", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_DE_CBBLE, "total_rounds_map_de_cbble", "#GAMEUI_Stat_RoundsMapDECbble", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_DE_CHATEAU, "total_rounds_map_de_chateau", "#GAMEUI_Stat_RoundsMapDEChateau", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_DE_DUST2, "total_rounds_map_de_dust2", "#GAMEUI_Stat_RoundsMapDEDust2", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_DE_DUST, "total_rounds_map_de_dust", "#GAMEUI_Stat_RoundsMapDEDust", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_DE_INFERNO, "total_rounds_map_de_inferno", "#GAMEUI_Stat_RoundsMapDEInferno", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_DE_NUKE, "total_rounds_map_de_nuke", "#GAMEUI_Stat_RoundsMapDENuke", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_DE_PIRANESI, "total_rounds_map_de_piranesi", "#GAMEUI_Stat_RoundsMapDEPiranesi", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_DE_PORT, "total_rounds_map_de_port", "#GAMEUI_Stat_RoundsMapDEPort", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_DE_PRODIGY, "total_rounds_map_de_prodigy", "#GAMEUI_Stat_RoundsMapDEProdigy", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_DE_TIDES, "total_rounds_map_de_tides", "#GAMEUI_Stat_RoundsMapDETides", CSSTAT_PRIORITY_ENDROUND, },
|
||||
{ CSSTAT_MAP_ROUNDS_DE_TRAIN, "total_rounds_map_de_train", "#GAMEUI_Stat_RoundsMapDETrain", CSSTAT_PRIORITY_ENDROUND, },
|
||||
|
||||
// only client tracks these
|
||||
{ CSSTAT_LASTMATCH_T_ROUNDS_WON, "last_match_t_wins", "#GameUI_Stat_LastMatch_TWins", CSSTAT_PRIORITY_NEVER },
|
||||
{ CSSTAT_LASTMATCH_CT_ROUNDS_WON, "last_match_ct_wins", "#GameUI_Stat_LastMatch_CTWins", CSSTAT_PRIORITY_NEVER },
|
||||
{ CSSTAT_LASTMATCH_ROUNDS_WON, "last_match_wins", "#GameUI_Stat_LastMatch_RoundsWon", CSSTAT_PRIORITY_NEVER },
|
||||
{ CSSTAT_LASTMATCH_KILLS, "last_match_kills", "#GameUI_Stat_LastMatch_Kills", CSSTAT_PRIORITY_NEVER },
|
||||
{ CSSTAT_LASTMATCH_DEATHS, "last_match_deaths", "#GameUI_Stat_LastMatch_Deaths", CSSTAT_PRIORITY_NEVER },
|
||||
{ CSSTAT_LASTMATCH_MVPS, "last_match_mvps", "#GameUI_Stat_LastMatch_MVPS", CSSTAT_PRIORITY_NEVER },
|
||||
{ CSSTAT_LASTMATCH_DAMAGE, "last_match_damage", "#GameUI_Stat_LastMatch_Damage", CSSTAT_PRIORITY_NEVER },
|
||||
{ CSSTAT_LASTMATCH_MONEYSPENT, "last_match_money_spent", "#GameUI_Stat_LastMatch_MoneySpent", CSSTAT_PRIORITY_NEVER },
|
||||
{ CSSTAT_LASTMATCH_DOMINATIONS, "last_match_dominations", "#GameUI_Stat_LastMatch_Dominations", CSSTAT_PRIORITY_NEVER },
|
||||
{ CSSTAT_LASTMATCH_REVENGES, "last_match_revenges", "#GameUI_Stat_LastMatch_Revenges", CSSTAT_PRIORITY_NEVER },
|
||||
{ CSSTAT_LASTMATCH_MAX_PLAYERS, "last_match_max_players", "#GameUI_Stat_LastMatch_MaxPlayers", CSSTAT_PRIORITY_NEVER },
|
||||
{ CSSTAT_LASTMATCH_FAVWEAPON_ID, "last_match_favweapon_id", "#GameUI_Stat_LastMatch_FavWeapon", CSSTAT_PRIORITY_NEVER },
|
||||
{ CSSTAT_LASTMATCH_FAVWEAPON_SHOTS, "last_match_favweapon_shots", "#GameUI_Stat_LastMatch_FavWeaponShots",CSSTAT_PRIORITY_NEVER },
|
||||
{ CSSTAT_LASTMATCH_FAVWEAPON_HITS, "last_match_favweapon_hits", "#GameUI_Stat_LastMatch_FavWeaponHits", CSSTAT_PRIORITY_NEVER },
|
||||
{ CSSTAT_LASTMATCH_FAVWEAPON_KILLS, "last_match_favweapon_kills", "#GameUI_Stat_LastMatch_FavWeaponKills",CSSTAT_PRIORITY_NEVER },
|
||||
|
||||
{ CSSTAT_UNDEFINED }, // sentinel
|
||||
};
|
||||
|
||||
const WeaponName_StatId& GetWeaponTableEntryFromWeaponId( CSWeaponID id )
|
||||
{
|
||||
int i;
|
||||
|
||||
//yes this for loop has no statement block. All we are doing is incrementing i to the appropriate point.
|
||||
for (i = 0 ; WeaponName_StatId_Table[i].weaponId != WEAPON_NONE ; ++i)
|
||||
{
|
||||
if (WeaponName_StatId_Table[i].weaponId == id )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return WeaponName_StatId_Table[i];
|
||||
}
|
||||
|
||||
void StatsCollection_t::Aggregate( const StatsCollection_t& other )
|
||||
{
|
||||
for ( int i = 0; i < CSSTAT_MAX; ++i )
|
||||
{
|
||||
m_iValue[i] += other[i];
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Helper functions for creating key values
|
||||
//
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, int data )
|
||||
{
|
||||
pKV->SetInt( name, data );
|
||||
}
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, uint64 data )
|
||||
{
|
||||
pKV->SetUint64( name, data );
|
||||
}
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, float data )
|
||||
{
|
||||
pKV->SetFloat( name, data );
|
||||
}
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, bool data )
|
||||
{
|
||||
pKV->SetInt( name, data ? true : false );
|
||||
}
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, const char* data )
|
||||
{
|
||||
pKV->SetString( name, data );
|
||||
}
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, const Color& data )
|
||||
{
|
||||
pKV->SetColor( name, data );
|
||||
}
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, short data )
|
||||
{
|
||||
pKV->SetInt( name, data );
|
||||
}
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, unsigned data )
|
||||
{
|
||||
pKV->SetInt( name, data );
|
||||
}
|
||||
void AddPositionDataToKV( KeyValues* pKV, const char* name, const Vector &data )
|
||||
{
|
||||
// Append the data name to the member
|
||||
pKV->SetFloat( CFmtStr("%s%s", name, "_X"), data.x );
|
||||
pKV->SetFloat( CFmtStr("%s%s", name, "_Y"), data.y );
|
||||
pKV->SetFloat( CFmtStr("%s%s", name, "_Z"), data.z );
|
||||
}
|
||||
|
||||
//=============================================================================//
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Helper functions for creating key values from arrays
|
||||
//
|
||||
void AddArrayDataToKV( KeyValues* pKV, const char* name, const short *data, unsigned size )
|
||||
{
|
||||
for( unsigned i=0; i<size; ++i )
|
||||
pKV->SetInt( CFmtStr("%s_%d", name, i) , data[i] );
|
||||
}
|
||||
void AddArrayDataToKV( KeyValues* pKV, const char* name, const byte *data, unsigned size )
|
||||
{
|
||||
for( unsigned i=0; i<size; ++i )
|
||||
pKV->SetInt( CFmtStr("%s_%d", name, i), data[i] );
|
||||
}
|
||||
void AddArrayDataToKV( KeyValues* pKV, const char* name, const unsigned *data, unsigned size )
|
||||
{
|
||||
for( unsigned i=0; i<size; ++i )
|
||||
pKV->SetInt( CFmtStr("%s_%d", name, i), data[i] );
|
||||
}
|
||||
void AddStringDataToKV( KeyValues* pKV, const char* name, const char*data )
|
||||
{
|
||||
if( name == NULL )
|
||||
return;
|
||||
|
||||
pKV->SetString( name, data );
|
||||
}
|
||||
//=============================================================================//
|
||||
|
||||
|
||||
void IGameStatTracker::PrintGamestatMemoryUsage( void )
|
||||
{
|
||||
StatContainerList_t* pStatList = GetStatContainerList();
|
||||
if( !pStatList )
|
||||
return;
|
||||
|
||||
int iListSize = pStatList->Count();
|
||||
|
||||
// For every stat list being tracked, print out its memory usage
|
||||
for( int i=0; i < iListSize; ++i )
|
||||
{
|
||||
pStatList->operator []( i )->PrintMemoryUsage();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,824 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
#ifndef CS_GAMESTATS_SHARED_H
|
||||
#define CS_GAMESTATS_SHARED_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
#include "cbase.h"
|
||||
// #include "tier1/utlvector.h"
|
||||
// #include "tier1/utldict.h"
|
||||
#include "shareddefs.h"
|
||||
#include "cs_shareddefs.h"
|
||||
#include "cs_weapon_parse.h"
|
||||
#include "fmtstr.h"
|
||||
|
||||
|
||||
#define CS_NUM_LEVELS 18
|
||||
|
||||
//=============================================================================
|
||||
// Helper class for simple manipulation of bit arrays.
|
||||
// Used for server->client packets containing delta stats
|
||||
//=============================================================================
|
||||
|
||||
template <int BitLength>
|
||||
class BitArray
|
||||
{
|
||||
enum { ByteLength = (BitLength + 7) / 8 };
|
||||
public:
|
||||
BitArray() { ClearAll(); }
|
||||
|
||||
void SetBit(int n) { m_bytes[n / 8] |= 1 << (n & 7); }
|
||||
void ClearBit(int n) { m_bytes[n / 8] &= (~(1 << (n & 7))); }
|
||||
bool IsBitSet(int n) const { return (m_bytes[n / 8] & (1 << (n & 7))) != 0;}
|
||||
|
||||
void ClearAll() { V_memset(m_bytes, 0, sizeof(m_bytes)); }
|
||||
int NumBits() { return BitLength; }
|
||||
int NumBytes() { return ByteLength; }
|
||||
|
||||
byte* RawPointer() { return m_bytes; }
|
||||
|
||||
private:
|
||||
byte m_bytes[ByteLength];
|
||||
};
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// CS Game Stats Enums
|
||||
//
|
||||
// WARNING! ANY CHANGE TO THE ORDERING OR NUMBER OF STATS WILL REQUIRE
|
||||
// SYNCHRONOUS UPDATE OF CLIENT AND SERVER DLLS. If you change these enums
|
||||
// (including adding new stats) without forcing an update of both the client
|
||||
// and server, stats will become corrupted on the game client and these
|
||||
// corrupted values will be uploaded to steam, which is very very bad.
|
||||
//
|
||||
// If you add new stats, if will be safest to add them at the end of the enum
|
||||
// (although this will still require a server update); make sure you also add
|
||||
// the stats to the CSStatProperty_Table in cs_gamestats_shared.cpp at the
|
||||
// appropriate location.
|
||||
|
||||
enum CSStatType_t
|
||||
{
|
||||
CSSTAT_UNDEFINED = -1,
|
||||
CSSTAT_SHOTS_HIT,
|
||||
CSSTAT_SHOTS_FIRED,
|
||||
CSSTAT_KILLS,
|
||||
CSSTAT_DEATHS,
|
||||
CSSTAT_DAMAGE,
|
||||
CSSTAT_NUM_BOMBS_PLANTED,
|
||||
CSSTAT_NUM_BOMBS_DEFUSED,
|
||||
CSSTAT_PLAYTIME,
|
||||
CSSTAT_ROUNDS_WON,
|
||||
CSSTAT_T_ROUNDS_WON,
|
||||
CSSTAT_CT_ROUNDS_WON,
|
||||
CSSTAT_ROUNDS_PLAYED,
|
||||
CSSTAT_PISTOLROUNDS_WON,
|
||||
CSSTAT_MONEY_EARNED,
|
||||
CSSTAT_OBJECTIVES_COMPLETED,
|
||||
CSSTAT_BOMBS_DEFUSED_WITHKIT,
|
||||
|
||||
CSSTAT_KILLS_DEAGLE,
|
||||
CSSTAT_KILLS_USP,
|
||||
CSSTAT_KILLS_GLOCK,
|
||||
CSSTAT_KILLS_P228,
|
||||
CSSTAT_KILLS_ELITE,
|
||||
CSSTAT_KILLS_FIVESEVEN,
|
||||
CSSTAT_KILLS_AWP,
|
||||
CSSTAT_KILLS_AK47,
|
||||
CSSTAT_KILLS_M4A1,
|
||||
CSSTAT_KILLS_AUG,
|
||||
CSSTAT_KILLS_SG552,
|
||||
CSSTAT_KILLS_SG550,
|
||||
CSSTAT_KILLS_GALIL,
|
||||
CSSTAT_KILLS_FAMAS,
|
||||
CSSTAT_KILLS_SCOUT,
|
||||
CSSTAT_KILLS_G3SG1,
|
||||
CSSTAT_KILLS_P90,
|
||||
CSSTAT_KILLS_MP5NAVY,
|
||||
CSSTAT_KILLS_TMP,
|
||||
CSSTAT_KILLS_MAC10,
|
||||
CSSTAT_KILLS_UMP45,
|
||||
CSSTAT_KILLS_M3,
|
||||
CSSTAT_KILLS_XM1014,
|
||||
CSSTAT_KILLS_M249,
|
||||
CSSTAT_KILLS_KNIFE,
|
||||
CSSTAT_KILLS_HEGRENADE,
|
||||
|
||||
CSSTAT_SHOTS_DEAGLE,
|
||||
CSSTAT_SHOTS_USP,
|
||||
CSSTAT_SHOTS_GLOCK,
|
||||
CSSTAT_SHOTS_P228,
|
||||
CSSTAT_SHOTS_ELITE,
|
||||
CSSTAT_SHOTS_FIVESEVEN,
|
||||
CSSTAT_SHOTS_AWP,
|
||||
CSSTAT_SHOTS_AK47,
|
||||
CSSTAT_SHOTS_M4A1,
|
||||
CSSTAT_SHOTS_AUG,
|
||||
CSSTAT_SHOTS_SG552,
|
||||
CSSTAT_SHOTS_SG550,
|
||||
CSSTAT_SHOTS_GALIL,
|
||||
CSSTAT_SHOTS_FAMAS,
|
||||
CSSTAT_SHOTS_SCOUT,
|
||||
CSSTAT_SHOTS_G3SG1,
|
||||
CSSTAT_SHOTS_P90,
|
||||
CSSTAT_SHOTS_MP5NAVY,
|
||||
CSSTAT_SHOTS_TMP,
|
||||
CSSTAT_SHOTS_MAC10,
|
||||
CSSTAT_SHOTS_UMP45,
|
||||
CSSTAT_SHOTS_M3,
|
||||
CSSTAT_SHOTS_XM1014,
|
||||
CSSTAT_SHOTS_M249,
|
||||
CSSTAT_SHOTS_KNIFE,
|
||||
CSSTAT_SHOTS_HEGRENADE,
|
||||
|
||||
CSSTAT_HITS_DEAGLE,
|
||||
CSSTAT_HITS_USP,
|
||||
CSSTAT_HITS_GLOCK,
|
||||
CSSTAT_HITS_P228,
|
||||
CSSTAT_HITS_ELITE,
|
||||
CSSTAT_HITS_FIVESEVEN,
|
||||
CSSTAT_HITS_AWP,
|
||||
CSSTAT_HITS_AK47,
|
||||
CSSTAT_HITS_M4A1,
|
||||
CSSTAT_HITS_AUG,
|
||||
CSSTAT_HITS_SG552,
|
||||
CSSTAT_HITS_SG550,
|
||||
CSSTAT_HITS_GALIL,
|
||||
CSSTAT_HITS_FAMAS,
|
||||
CSSTAT_HITS_SCOUT,
|
||||
CSSTAT_HITS_G3SG1,
|
||||
CSSTAT_HITS_P90,
|
||||
CSSTAT_HITS_MP5NAVY,
|
||||
CSSTAT_HITS_TMP,
|
||||
CSSTAT_HITS_MAC10,
|
||||
CSSTAT_HITS_UMP45,
|
||||
CSSTAT_HITS_M3,
|
||||
CSSTAT_HITS_XM1014,
|
||||
CSSTAT_HITS_M249,
|
||||
CSSTAT_HITS_KNIFE,
|
||||
CSSTAT_HITS_HEGRENADE,
|
||||
|
||||
CSSTAT_DAMAGE_DEAGLE,
|
||||
CSSTAT_DAMAGE_USP,
|
||||
CSSTAT_DAMAGE_GLOCK,
|
||||
CSSTAT_DAMAGE_P228,
|
||||
CSSTAT_DAMAGE_ELITE,
|
||||
CSSTAT_DAMAGE_FIVESEVEN,
|
||||
CSSTAT_DAMAGE_AWP,
|
||||
CSSTAT_DAMAGE_AK47,
|
||||
CSSTAT_DAMAGE_M4A1,
|
||||
CSSTAT_DAMAGE_AUG,
|
||||
CSSTAT_DAMAGE_SG552,
|
||||
CSSTAT_DAMAGE_SG550,
|
||||
CSSTAT_DAMAGE_GALIL,
|
||||
CSSTAT_DAMAGE_FAMAS,
|
||||
CSSTAT_DAMAGE_SCOUT,
|
||||
CSSTAT_DAMAGE_G3SG1,
|
||||
CSSTAT_DAMAGE_P90,
|
||||
CSSTAT_DAMAGE_MP5NAVY,
|
||||
CSSTAT_DAMAGE_TMP,
|
||||
CSSTAT_DAMAGE_MAC10,
|
||||
CSSTAT_DAMAGE_UMP45,
|
||||
CSSTAT_DAMAGE_M3,
|
||||
CSSTAT_DAMAGE_XM1014,
|
||||
CSSTAT_DAMAGE_M249,
|
||||
CSSTAT_DAMAGE_KNIFE,
|
||||
CSSTAT_DAMAGE_HEGRENADE,
|
||||
|
||||
CSSTAT_KILLS_HEADSHOT,
|
||||
CSSTAT_KILLS_ENEMY_BLINDED,
|
||||
CSSTAT_KILLS_WHILE_BLINDED,
|
||||
CSSTAT_KILLS_WITH_LAST_ROUND,
|
||||
CSSTAT_KILLS_ENEMY_WEAPON,
|
||||
CSSTAT_KILLS_KNIFE_FIGHT,
|
||||
CSSTAT_KILLS_WHILE_DEFENDING_BOMB,
|
||||
|
||||
CSSTAT_DECAL_SPRAYS,
|
||||
CSSTAT_TOTAL_JUMPS,
|
||||
CSSTAT_NIGHTVISION_DAMAGE,
|
||||
CSSTAT_KILLS_WHILE_LAST_PLAYER_ALIVE,
|
||||
CSSTAT_KILLS_ENEMY_WOUNDED,
|
||||
CSSTAT_FALL_DAMAGE,
|
||||
|
||||
CSSTAT_NUM_HOSTAGES_RESCUED,
|
||||
|
||||
CSSTAT_NUM_BROKEN_WINDOWS,
|
||||
CSSTAT_PROPSBROKEN_ALL,
|
||||
CSSTAT_PROPSBROKEN_MELON,
|
||||
CSSTAT_PROPSBROKEN_OFFICEELECTRONICS,
|
||||
CSSTAT_PROPSBROKEN_OFFICERADIO,
|
||||
CSSTAT_PROPSBROKEN_OFFICEJUNK,
|
||||
CSSTAT_PROPSBROKEN_ITALY_MELON,
|
||||
|
||||
CSSTAT_KILLS_AGAINST_ZOOMED_SNIPER,
|
||||
|
||||
CSSTAT_WEAPONS_DONATED,
|
||||
|
||||
CSSTAT_ITEMS_PURCHASED,
|
||||
CSSTAT_MONEY_SPENT,
|
||||
|
||||
CSSTAT_DOMINATIONS,
|
||||
CSSTAT_DOMINATION_OVERKILLS,
|
||||
CSSTAT_REVENGES,
|
||||
|
||||
CSSTAT_MVPS,
|
||||
|
||||
CSSTAT_GRENADE_DAMAGE,
|
||||
CSSTAT_GRENADE_POSTHUMOUSKILLS,
|
||||
CSSTAT_GRENADES_THROWN,
|
||||
|
||||
CSTAT_ITEMS_DROPPED_VALUE,
|
||||
|
||||
//Map win stats
|
||||
CSSTAT_MAP_WINS_CS_ASSAULT,
|
||||
CSSTAT_MAP_WINS_CS_COMPOUND,
|
||||
CSSTAT_MAP_WINS_CS_HAVANA,
|
||||
CSSTAT_MAP_WINS_CS_ITALY,
|
||||
CSSTAT_MAP_WINS_CS_MILITIA,
|
||||
CSSTAT_MAP_WINS_CS_OFFICE,
|
||||
CSSTAT_MAP_WINS_DE_AZTEC,
|
||||
CSSTAT_MAP_WINS_DE_CBBLE,
|
||||
CSSTAT_MAP_WINS_DE_CHATEAU,
|
||||
CSSTAT_MAP_WINS_DE_DUST2,
|
||||
CSSTAT_MAP_WINS_DE_DUST,
|
||||
CSSTAT_MAP_WINS_DE_INFERNO,
|
||||
CSSTAT_MAP_WINS_DE_NUKE,
|
||||
CSSTAT_MAP_WINS_DE_PIRANESI,
|
||||
CSSTAT_MAP_WINS_DE_PORT,
|
||||
CSSTAT_MAP_WINS_DE_PRODIGY,
|
||||
CSSTAT_MAP_WINS_DE_TIDES,
|
||||
CSSTAT_MAP_WINS_DE_TRAIN,
|
||||
|
||||
CSSTAT_MAP_ROUNDS_CS_ASSAULT,
|
||||
CSSTAT_MAP_ROUNDS_CS_COMPOUND,
|
||||
CSSTAT_MAP_ROUNDS_CS_HAVANA,
|
||||
CSSTAT_MAP_ROUNDS_CS_ITALY,
|
||||
CSSTAT_MAP_ROUNDS_CS_MILITIA,
|
||||
CSSTAT_MAP_ROUNDS_CS_OFFICE,
|
||||
CSSTAT_MAP_ROUNDS_DE_AZTEC,
|
||||
CSSTAT_MAP_ROUNDS_DE_CBBLE,
|
||||
CSSTAT_MAP_ROUNDS_DE_CHATEAU,
|
||||
CSSTAT_MAP_ROUNDS_DE_DUST2,
|
||||
CSSTAT_MAP_ROUNDS_DE_DUST,
|
||||
CSSTAT_MAP_ROUNDS_DE_INFERNO,
|
||||
CSSTAT_MAP_ROUNDS_DE_NUKE,
|
||||
CSSTAT_MAP_ROUNDS_DE_PIRANESI,
|
||||
CSSTAT_MAP_ROUNDS_DE_PORT,
|
||||
CSSTAT_MAP_ROUNDS_DE_PRODIGY,
|
||||
CSSTAT_MAP_ROUNDS_DE_TIDES,
|
||||
CSSTAT_MAP_ROUNDS_DE_TRAIN,
|
||||
|
||||
CSSTAT_LASTMATCH_T_ROUNDS_WON,
|
||||
CSSTAT_LASTMATCH_CT_ROUNDS_WON,
|
||||
CSSTAT_LASTMATCH_ROUNDS_WON,
|
||||
CSSTAT_LASTMATCH_KILLS,
|
||||
CSSTAT_LASTMATCH_DEATHS,
|
||||
CSSTAT_LASTMATCH_MVPS,
|
||||
CSSTAT_LASTMATCH_DAMAGE,
|
||||
CSSTAT_LASTMATCH_MONEYSPENT,
|
||||
CSSTAT_LASTMATCH_DOMINATIONS,
|
||||
CSSTAT_LASTMATCH_REVENGES,
|
||||
CSSTAT_LASTMATCH_MAX_PLAYERS,
|
||||
CSSTAT_LASTMATCH_FAVWEAPON_ID,
|
||||
CSSTAT_LASTMATCH_FAVWEAPON_SHOTS,
|
||||
CSSTAT_LASTMATCH_FAVWEAPON_HITS,
|
||||
CSSTAT_LASTMATCH_FAVWEAPON_KILLS,
|
||||
|
||||
CSSTAT_MAX //Must be last entry.
|
||||
};
|
||||
|
||||
|
||||
#define CSSTAT_FIRST (CSSTAT_UNDEFINED+1)
|
||||
#define CSSTAT_LAST (CSSTAT_MAX-1)
|
||||
|
||||
//
|
||||
// CS Game Stats Flags
|
||||
//
|
||||
#define CSSTAT_PRIORITY_MASK 0x000F
|
||||
#define CSSTAT_PRIORITY_NEVER 0x0000 // not sent to client
|
||||
#define CSSTAT_PRIORITY_ENDROUND 0x0001 // sent at end of round
|
||||
#define CSSTAT_PRIORITY_LOW 0x0002 // sent every 2500ms
|
||||
#define CSSTAT_PRIORITY_HIGH 0x0003 // sent every 250ms
|
||||
|
||||
struct CSStatProperty
|
||||
{
|
||||
int statId; // verify that table ordering is correct
|
||||
const char* szSteamName; // name of the stat on steam
|
||||
const char* szLocalizationToken; // localization token for the stat
|
||||
uint flags; // priority flags for sending to client
|
||||
};
|
||||
|
||||
extern CSStatProperty CSStatProperty_Table[];
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// CS Player Round Stats
|
||||
//
|
||||
struct StatsCollection_t
|
||||
{
|
||||
StatsCollection_t() { Reset(); }
|
||||
|
||||
inline int Get( int i ) const
|
||||
{
|
||||
AssertMsg( i >= CSSTAT_FIRST && i < CSSTAT_MAX, "Stat index out of range!" );
|
||||
if ( i >= 0 )
|
||||
return m_iValue[ i ];
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void Set( int i, int nValue )
|
||||
{
|
||||
AssertMsg( i >= CSSTAT_FIRST && i < CSSTAT_MAX, "Stat index out of range!" );
|
||||
if ( i >= 0 )
|
||||
m_iValue[ i ] = nValue;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE( m_iValue ); i++ )
|
||||
{
|
||||
m_iValue[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int operator[] ( int index ) const
|
||||
{
|
||||
Assert(index >= 0 && index < ARRAYSIZE(m_iValue));
|
||||
return m_iValue[index];
|
||||
}
|
||||
|
||||
int& operator[] ( int index )
|
||||
{
|
||||
Assert(index >= 0 && index < ARRAYSIZE(m_iValue));
|
||||
return m_iValue[index];
|
||||
}
|
||||
|
||||
void Aggregate( const StatsCollection_t& other );
|
||||
|
||||
private:
|
||||
int m_iValue[CSSTAT_MAX];
|
||||
};
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [tj] A couple variations on the RoundStats structure to handle extra operations
|
||||
// for averaging and accumulating
|
||||
//=============================================================================
|
||||
struct RoundStatsDirectAverage_t
|
||||
{
|
||||
float m_fStat[CSSTAT_MAX];
|
||||
|
||||
|
||||
RoundStatsDirectAverage_t()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
||||
{
|
||||
m_fStat[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
RoundStatsDirectAverage_t& operator +=( const StatsCollection_t &other )
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
||||
{
|
||||
m_fStat[i] += other[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RoundStatsDirectAverage_t& operator /=( const float &divisor)
|
||||
{
|
||||
if (divisor > 0)
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
||||
{
|
||||
m_fStat[i] /= divisor;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RoundStatsDirectAverage_t& operator *=( const float &divisor)
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
||||
{
|
||||
m_fStat[i] *= divisor;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct RoundStatsRollingAverage_t
|
||||
{
|
||||
float m_fStat[CSSTAT_MAX];
|
||||
int m_numberOfDataSets;
|
||||
|
||||
RoundStatsRollingAverage_t()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
||||
{
|
||||
m_fStat[i] = 0;
|
||||
}
|
||||
m_numberOfDataSets = 0;
|
||||
}
|
||||
|
||||
RoundStatsRollingAverage_t& operator +=( const RoundStatsRollingAverage_t &other )
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
||||
{
|
||||
m_fStat[i] += other.m_fStat[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RoundStatsRollingAverage_t& operator +=( const StatsCollection_t &other )
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
||||
{
|
||||
m_fStat[i] += other[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RoundStatsRollingAverage_t& operator /=( const float &divisor)
|
||||
{
|
||||
if (divisor > 0)
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
||||
{
|
||||
m_fStat[i] /= divisor;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void RollDataSetIntoAverage ( const RoundStatsRollingAverage_t &other )
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
||||
{
|
||||
m_fStat[i] *= m_numberOfDataSets;
|
||||
m_fStat[i] += other.m_fStat[i];
|
||||
m_fStat[i] /= (m_numberOfDataSets + 1);
|
||||
}
|
||||
m_numberOfDataSets++;
|
||||
}
|
||||
};
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
enum CSGameStatsVersions_t
|
||||
{
|
||||
CS_GAMESTATS_FILE_VERSION = 006,
|
||||
CS_GAMESTATS_MAGIC = 0xDEADBEEF
|
||||
};
|
||||
|
||||
struct CS_Gamestats_Version_t
|
||||
{
|
||||
int m_iMagic; // always CS_GAMESTATS_MAGIC
|
||||
int m_iVersion;
|
||||
};
|
||||
|
||||
|
||||
struct KillStats_t
|
||||
{
|
||||
KillStats_t() { Reset(); }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
Q_memset( iNumKilled, 0, sizeof( iNumKilled ) );
|
||||
Q_memset( iNumKilledBy, 0, sizeof( iNumKilledBy ) );
|
||||
Q_memset( iNumKilledByUnanswered, 0, sizeof( iNumKilledByUnanswered ) );
|
||||
}
|
||||
|
||||
int iNumKilled[MAX_PLAYERS+1]; // how many times this player has killed each other player
|
||||
int iNumKilledBy[MAX_PLAYERS+1]; // how many times this player has been killed by each other player
|
||||
int iNumKilledByUnanswered[MAX_PLAYERS+1]; // how many unanswered kills this player has been dealt by each other player
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// CS Player Stats
|
||||
//
|
||||
struct PlayerStats_t
|
||||
{
|
||||
PlayerStats_t()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
statsDelta.Reset();
|
||||
statsCurrentRound.Reset();
|
||||
statsCurrentMatch.Reset();
|
||||
statsKills.Reset();
|
||||
}
|
||||
|
||||
PlayerStats_t( const PlayerStats_t &other )
|
||||
{
|
||||
statsDelta = other.statsDelta;
|
||||
statsCurrentRound = other.statsCurrentRound;
|
||||
statsCurrentMatch = other.statsCurrentMatch;
|
||||
}
|
||||
|
||||
StatsCollection_t statsDelta;
|
||||
StatsCollection_t statsCurrentRound;
|
||||
StatsCollection_t statsCurrentMatch;
|
||||
KillStats_t statsKills;
|
||||
};
|
||||
|
||||
|
||||
struct WeaponName_StatId
|
||||
{
|
||||
CSWeaponID weaponId;
|
||||
CSStatType_t killStatId;
|
||||
CSStatType_t shotStatId;
|
||||
CSStatType_t hitStatId;
|
||||
CSStatType_t damageStatId;
|
||||
};
|
||||
|
||||
struct MapName_MapStatId
|
||||
{
|
||||
const char* szMapName;
|
||||
CSStatType_t statWinsId;
|
||||
CSStatType_t statRoundsId;
|
||||
};
|
||||
|
||||
extern const MapName_MapStatId MapName_StatId_Table[];
|
||||
|
||||
//A mapping from weapon names to weapon stat IDs
|
||||
extern const WeaponName_StatId WeaponName_StatId_Table[];
|
||||
|
||||
//Used to look up the appropriate entry by the ID of the actual weapon
|
||||
const WeaponName_StatId& GetWeaponTableEntryFromWeaponId(CSWeaponID id);
|
||||
|
||||
#include "steamworks_gamestats.h"
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Helper functions for creating key values
|
||||
//
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, int data );
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, uint64 data );
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, float data );
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, bool data );
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, const char* data );
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, const Color& data );
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, short data );
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, unsigned data );
|
||||
void AddDataToKV( KeyValues* pKV, const char* name, const Vector& data );
|
||||
void AddPositionDataToKV( KeyValues* pKV, const char* name, const Vector &data );
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Helper functions for creating key values from arrays
|
||||
//
|
||||
void AddArrayDataToKV( KeyValues* pKV, const char* name, const short *data, unsigned size );
|
||||
void AddArrayDataToKV( KeyValues* pKV, const char* name, const byte *data, unsigned size );
|
||||
void AddArrayDataToKV( KeyValues* pKV, const char* name, const unsigned *data, unsigned size );
|
||||
void AddStringDataToKV( KeyValues* pKV, const char* name, const char *data );
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// Macros to ease the creation of SendData method for stats structs/classes
|
||||
#define BEGIN_STAT_TABLE( tableName ) \
|
||||
static const char* GetStatTableName( void ) { return tableName; } \
|
||||
void BuildGamestatDataTable( KeyValues* pKV ) \
|
||||
{ \
|
||||
pKV->SetName( GetStatTableName() );
|
||||
|
||||
#define REGISTER_STAT( varName ) \
|
||||
AddDataToKV(pKV, #varName, varName);
|
||||
|
||||
#define REGISTER_STAT_NAMED( varName, dbName ) \
|
||||
AddDataToKV(pKV, dbName, varName);
|
||||
|
||||
#define REGISTER_STAT_POSITION( varName ) \
|
||||
AddPositionDataToKV(pKV, #varName, varName);
|
||||
|
||||
#define REGISTER_STAT_POSITION_NAMED( varName, dbName ) \
|
||||
AddPositionDataToKV(pKV, dbName, varName);
|
||||
|
||||
#define REGISTER_STAT_ARRAY( varName ) \
|
||||
AddArrayDataToKV( pKV, #varName, varName, ARRAYSIZE( varName ) );
|
||||
|
||||
#define REGISTER_STAT_ARRAY_NAMED( varName, dbName ) \
|
||||
AddArrayDataToKV( pKV, dbName, varName, ARRAYSIZE( varName ) );
|
||||
|
||||
#define REGISTER_STAT_STRING( varName ) \
|
||||
AddStringDataToKV( pKV, #varName, varName );
|
||||
|
||||
#define REGISTER_STAT_STRING_NAMED( varName, dbName ) \
|
||||
AddStringDataToKV( pKV, dbName, varName );
|
||||
|
||||
#define AUTO_STAT_TABLE_KEY() \
|
||||
pKV->SetInt( "TimeSubmitted", GetUniqueIDForStatTable( *this ) );
|
||||
|
||||
#define END_STAT_TABLE() \
|
||||
pKV->SetUint64( ::BaseStatData::m_bUseGlobalData ? "TimeSubmitted" : "SessionTime", ::BaseStatData::TimeSubmitted ); \
|
||||
GetSteamWorksSGameStatsUploader().AddStatsForUpload( pKV ); \
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Templatized class for getting unique ID's for stat tables that need
|
||||
// to be submitted multiple times per-session.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template < typename T >
|
||||
class UniqueStatID_t
|
||||
{
|
||||
public:
|
||||
static unsigned GetNext( void )
|
||||
{
|
||||
return ++s_nLastID;
|
||||
}
|
||||
|
||||
static void Reset( void )
|
||||
{
|
||||
s_nLastID = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
static unsigned s_nLastID;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
unsigned UniqueStatID_t< T >::s_nLastID = 0;
|
||||
|
||||
template < typename T >
|
||||
unsigned GetUniqueIDForStatTable( const T &table )
|
||||
{
|
||||
return UniqueStatID_t< T >::GetNext();
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// An interface for tracking gamestats.
|
||||
//
|
||||
class IGameStatTracker
|
||||
{
|
||||
public:
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Templatized methods to track a per-mission stat.
|
||||
// The stat is copied, then deleted after it's sent to the SQL server.
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename T >
|
||||
void SubmitStat( T& stat )
|
||||
{
|
||||
// Make a copy of the stat. All of the stat lists require pointers,
|
||||
// so we need to protect against a stat allocated on the stack
|
||||
T* pT = new T();
|
||||
if( !pT )
|
||||
return;
|
||||
|
||||
*pT = stat;
|
||||
SubmitStat( pT );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Templatized methods to track a per-mission stat (by pointer)
|
||||
// The stat is deleted after it's sent to the SQL server
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename T >
|
||||
void SubmitStat( T* pStat )
|
||||
{
|
||||
// Get the static stat table for this type and add the stat to it
|
||||
GetStatTable<T>()->AddToTail( pStat );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Add all stats to an existing key value file for submit.
|
||||
//-----------------------------------------------------------------------------
|
||||
virtual void SubmitGameStats( KeyValues *pKV ) = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Prints the memory usage of all of the stats being tracked
|
||||
//-----------------------------------------------------------------------------
|
||||
void PrintGamestatMemoryUsage( void );
|
||||
|
||||
protected:
|
||||
//=============================================================================
|
||||
//
|
||||
// Used as a base interface to store a list of all templatized stat containers
|
||||
//
|
||||
class IStatContainer
|
||||
{
|
||||
public:
|
||||
virtual void SendData( KeyValues *pKV ) = 0;
|
||||
virtual void Clear( void ) = 0;
|
||||
virtual void PrintMemoryUsage( void ) = 0;
|
||||
};
|
||||
|
||||
// Defines a list of stat containers.
|
||||
typedef CUtlVector< IStatContainer* > StatContainerList_t;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Used to get a list of all stats containers being tracked by the deriving class
|
||||
//-----------------------------------------------------------------------------
|
||||
virtual StatContainerList_t* GetStatContainerList( void ) = 0;
|
||||
|
||||
private:
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Templatized list of stats submitted
|
||||
//
|
||||
template < typename T >
|
||||
class CGameStatList : public IStatContainer, public CUtlVector< T* >
|
||||
{
|
||||
public:
|
||||
//-----------------------------------------------------------------------------
|
||||
// Get data ready to send to the SQL server
|
||||
//-----------------------------------------------------------------------------
|
||||
virtual void SendData( KeyValues *pKV )
|
||||
{
|
||||
//ASSERT( pKV != NULL );
|
||||
|
||||
// Duplicate the master KeyValue for each stat instance
|
||||
for( int i=0; i < this->m_Size; ++i )
|
||||
{
|
||||
// Make a copy of the master key value and build the stat table
|
||||
KeyValues *pKVCopy = this->operator [](i)->m_bUseGlobalData ? pKV->MakeCopy() : new KeyValues( "" );
|
||||
this->operator [](i)->BuildGamestatDataTable( pKVCopy );
|
||||
}
|
||||
|
||||
// Reset unique ID counter for the stat type
|
||||
UniqueStatID_t< T >::Reset();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Clear and delete every stat in this list
|
||||
//-----------------------------------------------------------------------------
|
||||
virtual void Clear( void )
|
||||
{
|
||||
this->PurgeAndDeleteElements();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Print out details about this lists memory usage
|
||||
//-----------------------------------------------------------------------------
|
||||
virtual void PrintMemoryUsage( void )
|
||||
{
|
||||
if( this->m_Size == 0 )
|
||||
return;
|
||||
|
||||
// Compute the memory used as the size of type times the list count
|
||||
unsigned uMemoryUsed = this->m_Size * ( sizeof( T ) );
|
||||
|
||||
Msg( " %d\tbytes used by %s table\n", uMemoryUsed, T::GetStatTableName() );
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Templatized method to get a single instance of a stat list per data type.
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename T >
|
||||
CGameStatList< T >* GetStatTable( void )
|
||||
{
|
||||
static CGameStatList< T > *s_vecOfType = 0;
|
||||
if( s_vecOfType == 0 )
|
||||
{
|
||||
s_vecOfType = new CGameStatList< T >();
|
||||
GetStatContainerList()->AddToTail( s_vecOfType );
|
||||
}
|
||||
return s_vecOfType;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct BaseStatData
|
||||
{
|
||||
BaseStatData( bool bUseGlobalData = true ) : m_bUseGlobalData( bUseGlobalData )
|
||||
{
|
||||
TimeSubmitted = GetSteamWorksSGameStatsUploader().GetTimeSinceEpoch();
|
||||
}
|
||||
|
||||
bool m_bUseGlobalData;
|
||||
uint64 TimeSubmitted;
|
||||
|
||||
};
|
||||
|
||||
extern ConVar sv_noroundstats;
|
||||
|
||||
#endif // CS_GAMESTATS_SHARED_H
|
||||
@@ -0,0 +1,943 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "decals.h"
|
||||
#include "cs_gamerules.h"
|
||||
#include "weapon_c4.h"
|
||||
#include "in_buttons.h"
|
||||
#include "datacache/imdlcache.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_cs_player.h"
|
||||
#else
|
||||
#include "cs_player.h"
|
||||
#include "soundent.h"
|
||||
#include "bot/cs_bot.h"
|
||||
#include "KeyValues.h"
|
||||
#include "triggers.h"
|
||||
#include "cs_gamestats.h"
|
||||
#endif
|
||||
|
||||
#include "cs_playeranimstate.h"
|
||||
#include "basecombatweapon_shared.h"
|
||||
#include "util_shared.h"
|
||||
#include "takedamageinfo.h"
|
||||
#include "effect_dispatch_data.h"
|
||||
#include "engine/ivdebugoverlay.h"
|
||||
#include "obstacle_pushaway.h"
|
||||
#include "props_shared.h"
|
||||
|
||||
ConVar sv_showimpacts("sv_showimpacts", "0", FCVAR_REPLICATED, "Shows client (red) and server (blue) bullet impact point (1=both, 2=client-only, 3=server-only)" );
|
||||
ConVar sv_showplayerhitboxes( "sv_showplayerhitboxes", "0", FCVAR_REPLICATED, "Show lag compensated hitboxes for the specified player index whenever a player fires." );
|
||||
|
||||
#define CS_MASK_SHOOT (MASK_SOLID|CONTENTS_DEBRIS)
|
||||
|
||||
void DispatchEffect( const char *pName, const CEffectData &data );
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
// This is some extra code to collect weapon accuracy stats:
|
||||
|
||||
struct bulletdata_s
|
||||
{
|
||||
float timedelta; // time delta since first shot of this round
|
||||
float derivation; // derivation for first shoot view angle
|
||||
int count;
|
||||
};
|
||||
|
||||
#define STATS_MAX_BULLETS 50
|
||||
|
||||
static bulletdata_s s_bullet_stats[STATS_MAX_BULLETS];
|
||||
|
||||
Vector s_firstImpact = Vector(0,0,0);
|
||||
float s_firstTime = 0;
|
||||
float s_LastTime = 0;
|
||||
int s_bulletCount = 0;
|
||||
|
||||
void ResetBulletStats()
|
||||
{
|
||||
s_firstTime = 0;
|
||||
s_LastTime = 0;
|
||||
s_bulletCount = 0;
|
||||
s_firstImpact = Vector(0,0,0);
|
||||
Q_memset( s_bullet_stats, 0, sizeof(s_bullet_stats) );
|
||||
}
|
||||
|
||||
void PrintBulletStats()
|
||||
{
|
||||
for (int i=0; i<STATS_MAX_BULLETS; i++ )
|
||||
{
|
||||
if (s_bullet_stats[i].count == 0)
|
||||
break;
|
||||
|
||||
Msg("%3i;%3i;%.4f;%.4f\n", i, s_bullet_stats[i].count,
|
||||
s_bullet_stats[i].timedelta, s_bullet_stats[i].derivation );
|
||||
}
|
||||
}
|
||||
|
||||
void AddBulletStat( float time, float dist, Vector &impact )
|
||||
{
|
||||
if ( time > s_LastTime + 2.0f )
|
||||
{
|
||||
// time delta since last shoot is bigger than 2 seconds, start new row
|
||||
s_LastTime = s_firstTime = time;
|
||||
s_bulletCount = 0;
|
||||
s_firstImpact = impact;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
s_LastTime = time;
|
||||
s_bulletCount++;
|
||||
}
|
||||
|
||||
if ( s_bulletCount >= STATS_MAX_BULLETS )
|
||||
s_bulletCount = STATS_MAX_BULLETS -1;
|
||||
|
||||
if ( dist < 1 )
|
||||
dist = 1;
|
||||
|
||||
int i = s_bulletCount;
|
||||
|
||||
float offset = VectorLength( s_firstImpact - impact );
|
||||
|
||||
float timedelta = time - s_firstTime;
|
||||
float derivation = offset / dist;
|
||||
|
||||
float weight = (float)s_bullet_stats[i].count/(float)(s_bullet_stats[i].count+1);
|
||||
|
||||
s_bullet_stats[i].timedelta *= weight;
|
||||
s_bullet_stats[i].timedelta += (1.0f-weight) * timedelta;
|
||||
|
||||
s_bullet_stats[i].derivation *= weight;
|
||||
s_bullet_stats[i].derivation += (1.0f-weight) * derivation;
|
||||
|
||||
s_bullet_stats[i].count++;
|
||||
}
|
||||
|
||||
CON_COMMAND( stats_bullets_reset, "Reset bullet stats")
|
||||
{
|
||||
ResetBulletStats();
|
||||
}
|
||||
|
||||
CON_COMMAND( stats_bullets_print, "Print bullet stats")
|
||||
{
|
||||
PrintBulletStats();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
float CCSPlayer::GetPlayerMaxSpeed()
|
||||
{
|
||||
if ( GetMoveType() == MOVETYPE_NONE )
|
||||
{
|
||||
return CS_PLAYER_SPEED_STOPPED;
|
||||
}
|
||||
|
||||
if ( IsObserver() )
|
||||
{
|
||||
// Player gets speed bonus in observer mode
|
||||
return CS_PLAYER_SPEED_OBSERVER;
|
||||
}
|
||||
|
||||
bool bValidMoveState = ( State_Get() == STATE_ACTIVE || State_Get() == STATE_OBSERVER_MODE );
|
||||
if ( !bValidMoveState || m_bIsDefusing || CSGameRules()->IsFreezePeriod() )
|
||||
{
|
||||
// Player should not move during the freeze period
|
||||
return CS_PLAYER_SPEED_STOPPED;
|
||||
}
|
||||
|
||||
float speed = BaseClass::GetPlayerMaxSpeed();
|
||||
|
||||
if ( IsVIP() == true ) // VIP is slow due to the armour he's wearing
|
||||
{
|
||||
speed = MIN(speed, CS_PLAYER_SPEED_VIP);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
CWeaponCSBase *pWeapon = dynamic_cast<CWeaponCSBase*>( GetActiveWeapon() );
|
||||
|
||||
if ( pWeapon )
|
||||
{
|
||||
if ( HasShield() && IsShieldDrawn() )
|
||||
{
|
||||
speed = MIN(speed, CS_PLAYER_SPEED_SHIELD);
|
||||
}
|
||||
else
|
||||
{
|
||||
speed = MIN(speed, pWeapon->GetMaxSpeed());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return speed;
|
||||
}
|
||||
|
||||
|
||||
void CCSPlayer::GetBulletTypeParameters(
|
||||
int iBulletType,
|
||||
float &fPenetrationPower,
|
||||
float &flPenetrationDistance )
|
||||
{
|
||||
//MIKETODO: make ammo types come from a script file.
|
||||
if ( IsAmmoType( iBulletType, BULLET_PLAYER_50AE ) )
|
||||
{
|
||||
fPenetrationPower = 30;
|
||||
flPenetrationDistance = 1000.0;
|
||||
}
|
||||
else if ( IsAmmoType( iBulletType, BULLET_PLAYER_762MM ) )
|
||||
{
|
||||
fPenetrationPower = 39;
|
||||
flPenetrationDistance = 5000.0;
|
||||
}
|
||||
else if ( IsAmmoType( iBulletType, BULLET_PLAYER_556MM ) ||
|
||||
IsAmmoType( iBulletType, BULLET_PLAYER_556MM_BOX ) )
|
||||
{
|
||||
fPenetrationPower = 35;
|
||||
flPenetrationDistance = 4000.0;
|
||||
}
|
||||
else if ( IsAmmoType( iBulletType, BULLET_PLAYER_338MAG ) )
|
||||
{
|
||||
fPenetrationPower = 45;
|
||||
flPenetrationDistance = 8000.0;
|
||||
}
|
||||
else if ( IsAmmoType( iBulletType, BULLET_PLAYER_9MM ) )
|
||||
{
|
||||
fPenetrationPower = 21;
|
||||
flPenetrationDistance = 800.0;
|
||||
}
|
||||
else if ( IsAmmoType( iBulletType, BULLET_PLAYER_BUCKSHOT ) )
|
||||
{
|
||||
fPenetrationPower = 0;
|
||||
flPenetrationDistance = 0.0;
|
||||
}
|
||||
else if ( IsAmmoType( iBulletType, BULLET_PLAYER_45ACP ) )
|
||||
{
|
||||
fPenetrationPower = 15;
|
||||
flPenetrationDistance = 500.0;
|
||||
}
|
||||
else if ( IsAmmoType( iBulletType, BULLET_PLAYER_357SIG ) )
|
||||
{
|
||||
fPenetrationPower = 25;
|
||||
flPenetrationDistance = 800.0;
|
||||
}
|
||||
else if ( IsAmmoType( iBulletType, BULLET_PLAYER_57MM ) )
|
||||
{
|
||||
fPenetrationPower = 30;
|
||||
flPenetrationDistance = 2000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// What kind of ammo is this?
|
||||
Assert( false );
|
||||
fPenetrationPower = 0;
|
||||
flPenetrationDistance = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
static void GetMaterialParameters( int iMaterial, float &flPenetrationModifier, float &flDamageModifier )
|
||||
{
|
||||
switch ( iMaterial )
|
||||
{
|
||||
case CHAR_TEX_METAL :
|
||||
flPenetrationModifier = 0.5; // If we hit metal, reduce the thickness of the brush we can't penetrate
|
||||
flDamageModifier = 0.3;
|
||||
break;
|
||||
case CHAR_TEX_DIRT :
|
||||
flPenetrationModifier = 0.5;
|
||||
flDamageModifier = 0.3;
|
||||
break;
|
||||
case CHAR_TEX_CONCRETE :
|
||||
flPenetrationModifier = 0.4;
|
||||
flDamageModifier = 0.25;
|
||||
break;
|
||||
case CHAR_TEX_GRATE :
|
||||
flPenetrationModifier = 1.0;
|
||||
flDamageModifier = 0.99;
|
||||
break;
|
||||
case CHAR_TEX_VENT :
|
||||
flPenetrationModifier = 0.5;
|
||||
flDamageModifier = 0.45;
|
||||
break;
|
||||
case CHAR_TEX_TILE :
|
||||
flPenetrationModifier = 0.65;
|
||||
flDamageModifier = 0.3;
|
||||
break;
|
||||
case CHAR_TEX_COMPUTER :
|
||||
flPenetrationModifier = 0.4;
|
||||
flDamageModifier = 0.45;
|
||||
break;
|
||||
case CHAR_TEX_WOOD :
|
||||
flPenetrationModifier = 1.0;
|
||||
flDamageModifier = 0.6;
|
||||
break;
|
||||
default :
|
||||
flPenetrationModifier = 1.0;
|
||||
flDamageModifier = 0.5;
|
||||
break;
|
||||
}
|
||||
|
||||
Assert( flPenetrationModifier > 0 );
|
||||
Assert( flDamageModifier < 1.0f ); // Less than 1.0f for avoiding infinite loops
|
||||
}
|
||||
|
||||
|
||||
static bool TraceToExit(Vector &start, Vector &dir, Vector &end, float flStepSize, float flMaxDistance )
|
||||
{
|
||||
float flDistance = 0;
|
||||
Vector last = start;
|
||||
|
||||
while ( flDistance <= flMaxDistance )
|
||||
{
|
||||
flDistance += flStepSize;
|
||||
|
||||
end = start + flDistance *dir;
|
||||
|
||||
if ( (UTIL_PointContents ( end ) & MASK_SOLID) == 0 )
|
||||
{
|
||||
// found first free point
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void UTIL_TraceLineIgnoreTwoEntities( const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int mask,
|
||||
const IHandleEntity *ignore, const IHandleEntity *ignore2, int collisionGroup, trace_t *ptr )
|
||||
{
|
||||
Ray_t ray;
|
||||
ray.Init( vecAbsStart, vecAbsEnd );
|
||||
CTraceFilterSkipTwoEntities traceFilter( ignore, ignore2, collisionGroup );
|
||||
enginetrace->TraceRay( ray, mask, &traceFilter, ptr );
|
||||
if( r_visualizetraces.GetBool() )
|
||||
{
|
||||
DebugDrawLine( ptr->startpos, ptr->endpos, 255, 0, 0, true, -1.0f );
|
||||
}
|
||||
}
|
||||
|
||||
void CCSPlayer::FireBullet(
|
||||
Vector vecSrc, // shooting postion
|
||||
const QAngle &shootAngles, //shooting angle
|
||||
float flDistance, // max distance
|
||||
int iPenetration, // how many obstacles can be penetrated
|
||||
int iBulletType, // ammo type
|
||||
int iDamage, // base damage
|
||||
float flRangeModifier, // damage range modifier
|
||||
CBaseEntity *pevAttacker, // shooter
|
||||
bool bDoEffects,
|
||||
float xSpread, float ySpread
|
||||
)
|
||||
{
|
||||
float fCurrentDamage = iDamage; // damage of the bullet at it's current trajectory
|
||||
float flCurrentDistance = 0.0; //distance that the bullet has traveled so far
|
||||
|
||||
Vector vecDirShooting, vecRight, vecUp;
|
||||
AngleVectors( shootAngles, &vecDirShooting, &vecRight, &vecUp );
|
||||
|
||||
// MIKETODO: put all the ammo parameters into a script file and allow for CS-specific params.
|
||||
float flPenetrationPower = 0; // thickness of a wall that this bullet can penetrate
|
||||
float flPenetrationDistance = 0; // distance at which the bullet is capable of penetrating a wall
|
||||
float flDamageModifier = 0.5; // default modification of bullets power after they go through a wall.
|
||||
float flPenetrationModifier = 1.f;
|
||||
|
||||
GetBulletTypeParameters( iBulletType, flPenetrationPower, flPenetrationDistance );
|
||||
|
||||
|
||||
if ( !pevAttacker )
|
||||
pevAttacker = this; // the default attacker is ourselves
|
||||
|
||||
// add the spray
|
||||
Vector vecDir = vecDirShooting + xSpread * vecRight + ySpread * vecUp;
|
||||
|
||||
VectorNormalize( vecDir );
|
||||
|
||||
//Adrian: visualize server/client player positions
|
||||
//This is used to show where the lag compesator thinks the player should be at.
|
||||
#if 0
|
||||
for ( int k = 1; k <= gpGlobals->maxClients; k++ )
|
||||
{
|
||||
CBasePlayer *clientClass = (CBasePlayer *)CBaseEntity::Instance( k );
|
||||
|
||||
if ( clientClass == NULL )
|
||||
continue;
|
||||
|
||||
if ( k == entindex() )
|
||||
continue;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
debugoverlay->AddBoxOverlay( clientClass->GetAbsOrigin(), clientClass->WorldAlignMins(), clientClass->WorldAlignMaxs(), QAngle( 0, 0, 0), 255,0,0,127, 4 );
|
||||
#else
|
||||
NDebugOverlay::Box( clientClass->GetAbsOrigin(), clientClass->WorldAlignMins(), clientClass->WorldAlignMaxs(), 0,0,255,127, 4 );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
//=============================================================================
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// [pfreese] Track number player entities killed with this bullet
|
||||
int iPenetrationKills = 0;
|
||||
|
||||
// [menglish] Increment the shots fired for this player
|
||||
CCS_GameStats.Event_ShotFired( this, GetActiveWeapon() );
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
bool bFirstHit = true;
|
||||
|
||||
CBasePlayer *lastPlayerHit = NULL;
|
||||
|
||||
if( sv_showplayerhitboxes.GetInt() > 0 )
|
||||
{
|
||||
CBasePlayer *lagPlayer = UTIL_PlayerByIndex( sv_showplayerhitboxes.GetInt() );
|
||||
if( lagPlayer )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
lagPlayer->DrawClientHitboxes(4, true);
|
||||
#else
|
||||
lagPlayer->DrawServerHitboxes(4, true);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
MDLCACHE_CRITICAL_SECTION();
|
||||
while ( fCurrentDamage > 0 )
|
||||
{
|
||||
Vector vecEnd = vecSrc + vecDir * flDistance;
|
||||
|
||||
trace_t tr; // main enter bullet trace
|
||||
|
||||
UTIL_TraceLineIgnoreTwoEntities( vecSrc, vecEnd, CS_MASK_SHOOT|CONTENTS_HITBOX, this, lastPlayerHit, COLLISION_GROUP_NONE, &tr );
|
||||
{
|
||||
CTraceFilterSkipTwoEntities filter( this, lastPlayerHit, COLLISION_GROUP_NONE );
|
||||
|
||||
// Check for player hitboxes extending outside their collision bounds
|
||||
const float rayExtension = 40.0f;
|
||||
UTIL_ClipTraceToPlayers( vecSrc, vecEnd + vecDir * rayExtension, CS_MASK_SHOOT|CONTENTS_HITBOX, &filter, &tr );
|
||||
}
|
||||
|
||||
lastPlayerHit = ToBasePlayer(tr.m_pEnt);
|
||||
|
||||
if ( tr.fraction == 1.0f )
|
||||
break; // we didn't hit anything, stop tracing shoot
|
||||
|
||||
#ifdef _DEBUG
|
||||
if ( bFirstHit )
|
||||
AddBulletStat( gpGlobals->realtime, VectorLength( vecSrc-tr.endpos), tr.endpos );
|
||||
#endif
|
||||
|
||||
bFirstHit = false;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
//
|
||||
// Propogate a bullet impact event
|
||||
// @todo Add this for shotgun pellets (which dont go thru here)
|
||||
//
|
||||
IGameEvent * event = gameeventmanager->CreateEvent( "bullet_impact" );
|
||||
if ( event )
|
||||
{
|
||||
event->SetInt( "userid", GetUserID() );
|
||||
event->SetFloat( "x", tr.endpos.x );
|
||||
event->SetFloat( "y", tr.endpos.y );
|
||||
event->SetFloat( "z", tr.endpos.z );
|
||||
gameeventmanager->FireEvent( event );
|
||||
}
|
||||
#endif
|
||||
|
||||
/************* MATERIAL DETECTION ***********/
|
||||
surfacedata_t *pSurfaceData = physprops->GetSurfaceData( tr.surface.surfaceProps );
|
||||
int iEnterMaterial = pSurfaceData->game.material;
|
||||
|
||||
GetMaterialParameters( iEnterMaterial, flPenetrationModifier, flDamageModifier );
|
||||
|
||||
bool hitGrate = tr.contents & CONTENTS_GRATE;
|
||||
|
||||
// since some railings in de_inferno are CONTENTS_GRATE but CHAR_TEX_CONCRETE, we'll trust the
|
||||
// CONTENTS_GRATE and use a high damage modifier.
|
||||
if ( hitGrate )
|
||||
{
|
||||
// If we're a concrete grate (TOOLS/TOOLSINVISIBLE texture) allow more penetrating power.
|
||||
flPenetrationModifier = 1.0f;
|
||||
flDamageModifier = 0.99f;
|
||||
}
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
if ( sv_showimpacts.GetInt() == 1 || sv_showimpacts.GetInt() == 2 )
|
||||
{
|
||||
// draw red client impact markers
|
||||
debugoverlay->AddBoxOverlay( tr.endpos, Vector(-2,-2,-2), Vector(2,2,2), 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
|
||||
if ( sv_showimpacts.GetInt() == 1 || sv_showimpacts.GetInt() == 3 )
|
||||
{
|
||||
// draw blue server impact markers
|
||||
NDebugOverlay::Box( tr.endpos, Vector(-2,-2,-2), Vector(2,2,2), 0,0,255,127, 4 );
|
||||
|
||||
if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() )
|
||||
{
|
||||
CBasePlayer *player = ToBasePlayer( tr.m_pEnt );
|
||||
player->DrawServerHitboxes( 4, true );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//calculate the damage based on the distance the bullet travelled.
|
||||
flCurrentDistance += tr.fraction * flDistance;
|
||||
fCurrentDamage *= pow (flRangeModifier, (flCurrentDistance / 500));
|
||||
|
||||
// check if we reach penetration distance, no more penetrations after that
|
||||
if (flCurrentDistance > flPenetrationDistance && iPenetration > 0)
|
||||
iPenetration = 0;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// This just keeps track of sounds for AIs (it doesn't play anything).
|
||||
CSoundEnt::InsertSound( SOUND_BULLET_IMPACT, tr.endpos, 400, 0.2f, this );
|
||||
#endif
|
||||
|
||||
int iDamageType = DMG_BULLET | DMG_NEVERGIB;
|
||||
|
||||
if( bDoEffects )
|
||||
{
|
||||
// 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, COLLISION_GROUP_NONE, &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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
} // bDoEffects
|
||||
|
||||
// add damage to entity that we hit
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
ClearMultiDamage();
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [pfreese] Check if enemy players were killed by this bullet, and if so,
|
||||
// add them to the iPenetrationKills count
|
||||
//=============================================================================
|
||||
|
||||
CBaseEntity *pEntity = tr.m_pEnt;
|
||||
|
||||
CTakeDamageInfo info( pevAttacker, pevAttacker, fCurrentDamage, iDamageType );
|
||||
CalculateBulletDamageForce( &info, iBulletType, vecDir, tr.endpos );
|
||||
pEntity->DispatchTraceAttack( info, vecDir, &tr );
|
||||
|
||||
bool bWasAlive = pEntity->IsAlive();
|
||||
|
||||
TraceAttackToTriggers( info, tr.startpos, tr.endpos, vecDir );
|
||||
|
||||
ApplyMultiDamage();
|
||||
|
||||
if (bWasAlive && !pEntity->IsAlive() && pEntity->IsPlayer() && pEntity->GetTeamNumber() != GetTeamNumber())
|
||||
{
|
||||
++iPenetrationKills;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
#endif
|
||||
|
||||
// check if bullet can penetrate another entity
|
||||
if ( iPenetration == 0 && !hitGrate )
|
||||
break; // no, stop
|
||||
|
||||
// If we hit a grate with iPenetration == 0, stop on the next thing we hit
|
||||
if ( iPenetration < 0 )
|
||||
break;
|
||||
|
||||
Vector penetrationEnd;
|
||||
|
||||
// try to penetrate object, maximum penetration is 128 inch
|
||||
if ( !TraceToExit( tr.endpos, vecDir, penetrationEnd, 24, 128 ) )
|
||||
break;
|
||||
|
||||
// find exact penetration exit
|
||||
trace_t exitTr;
|
||||
UTIL_TraceLine( penetrationEnd, tr.endpos, CS_MASK_SHOOT|CONTENTS_HITBOX, NULL, &exitTr );
|
||||
|
||||
if( exitTr.m_pEnt != tr.m_pEnt && exitTr.m_pEnt != NULL )
|
||||
{
|
||||
// something was blocking, trace again
|
||||
UTIL_TraceLine( penetrationEnd, tr.endpos, CS_MASK_SHOOT|CONTENTS_HITBOX, exitTr.m_pEnt, COLLISION_GROUP_NONE, &exitTr );
|
||||
}
|
||||
|
||||
// get material at exit point
|
||||
pSurfaceData = physprops->GetSurfaceData( exitTr.surface.surfaceProps );
|
||||
int iExitMaterial = pSurfaceData->game.material;
|
||||
|
||||
hitGrate = hitGrate && ( exitTr.contents & CONTENTS_GRATE );
|
||||
|
||||
// if enter & exit point is wood or metal we assume this is
|
||||
// a hollow crate or barrel and give a penetration bonus
|
||||
if ( iEnterMaterial == iExitMaterial )
|
||||
{
|
||||
if( iExitMaterial == CHAR_TEX_WOOD ||
|
||||
iExitMaterial == CHAR_TEX_METAL )
|
||||
{
|
||||
flPenetrationModifier *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
float flTraceDistance = VectorLength( exitTr.endpos - tr.endpos );
|
||||
|
||||
// check if bullet has enough power to penetrate this distance for this material
|
||||
if ( flTraceDistance > ( flPenetrationPower * flPenetrationModifier ) )
|
||||
break; // bullet hasn't enough power to penetrate this distance
|
||||
|
||||
// penetration was successful
|
||||
|
||||
// bullet did penetrate object, exit Decal
|
||||
if ( bDoEffects )
|
||||
{
|
||||
UTIL_ImpactTrace( &exitTr, iDamageType );
|
||||
}
|
||||
|
||||
//setup new start end parameters for successive trace
|
||||
|
||||
flPenetrationPower -= flTraceDistance / flPenetrationModifier;
|
||||
flCurrentDistance += flTraceDistance;
|
||||
|
||||
// NDebugOverlay::Box( exitTr.endpos, Vector(-2,-2,-2), Vector(2,2,2), 0,255,0,127, 8 );
|
||||
|
||||
vecSrc = exitTr.endpos;
|
||||
flDistance = (flDistance - flCurrentDistance) * 0.5;
|
||||
|
||||
// reduce damage power each time we hit something other than a grate
|
||||
fCurrentDamage *= flDamageModifier;
|
||||
|
||||
// reduce penetration counter
|
||||
iPenetration--;
|
||||
}
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [pfreese] If we killed at least two enemies with a single bullet, award the
|
||||
// TWO_WITH_ONE_SHOT achievement
|
||||
//=============================================================================
|
||||
|
||||
if (iPenetrationKills >= 2)
|
||||
{
|
||||
AwardAchievement(CSKillTwoWithOneShot);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void CCSPlayer::UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity )
|
||||
{
|
||||
float speedSqr = vecVelocity.AsVector2D().LengthSqr();
|
||||
|
||||
// the fastest walk is 135 ( scout ), see CCSGameMovement::CheckParameters()
|
||||
if ( speedSqr < 150.0 * 150.0 )
|
||||
return; // player is not running, no footsteps
|
||||
|
||||
BaseClass::UpdateStepSound( psurface, vecOrigin, vecVelocity );
|
||||
}
|
||||
|
||||
|
||||
// GOOSEMAN : Kick the view..
|
||||
void CCSPlayer::KickBack( float up_base, float lateral_base, float up_modifier, float lateral_modifier, float up_max, float lateral_max, int direction_change )
|
||||
{
|
||||
float flKickUp;
|
||||
float flKickLateral;
|
||||
|
||||
if (m_iShotsFired == 1) // This is the first round fired
|
||||
{
|
||||
flKickUp = up_base;
|
||||
flKickLateral = lateral_base;
|
||||
}
|
||||
else
|
||||
{
|
||||
flKickUp = up_base + m_iShotsFired*up_modifier;
|
||||
flKickLateral = lateral_base + m_iShotsFired*lateral_modifier;
|
||||
}
|
||||
|
||||
|
||||
QAngle angle = GetPunchAngle();
|
||||
|
||||
angle.x -= flKickUp;
|
||||
if ( angle.x < -1 * up_max )
|
||||
angle.x = -1 * up_max;
|
||||
|
||||
if ( m_iDirection == 1 )
|
||||
{
|
||||
angle.y += flKickLateral;
|
||||
if (angle.y > lateral_max)
|
||||
angle.y = lateral_max;
|
||||
}
|
||||
else
|
||||
{
|
||||
angle.y -= flKickLateral;
|
||||
if ( angle.y < -1 * lateral_max )
|
||||
angle.y = -1 * lateral_max;
|
||||
}
|
||||
|
||||
if ( !SharedRandomInt( "KickBack", 0, direction_change ) )
|
||||
m_iDirection = 1 - m_iDirection;
|
||||
|
||||
SetPunchAngle( angle );
|
||||
}
|
||||
|
||||
|
||||
bool CCSPlayer::CanMove() const
|
||||
{
|
||||
// When we're in intro camera mode, it's important to return false here
|
||||
// so our physics object doesn't fall out of the world.
|
||||
if ( GetMoveType() == MOVETYPE_NONE )
|
||||
return false;
|
||||
|
||||
if ( IsObserver() )
|
||||
return true; // observers can move all the time
|
||||
|
||||
bool bValidMoveState = (State_Get() == STATE_ACTIVE || State_Get() == STATE_OBSERVER_MODE);
|
||||
|
||||
if ( m_bIsDefusing || !bValidMoveState || CSGameRules()->IsFreezePeriod() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can't move while planting C4.
|
||||
CC4 *pC4 = dynamic_cast< CC4* >( GetActiveWeapon() );
|
||||
if ( pC4 && pC4->m_bStartedArming )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CCSPlayer::OnJump( float fImpulse )
|
||||
{
|
||||
CWeaponCSBase* pActiveWeapon = GetActiveCSWeapon();
|
||||
if ( pActiveWeapon != NULL )
|
||||
pActiveWeapon->OnJump(fImpulse);
|
||||
}
|
||||
|
||||
|
||||
void CCSPlayer::OnLand( float fVelocity )
|
||||
{
|
||||
CWeaponCSBase* pActiveWeapon = GetActiveCSWeapon();
|
||||
if ( pActiveWeapon != NULL )
|
||||
pActiveWeapon->OnLand(fVelocity);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Track the last time we were on a ladder, along with the ladder's normal and where we
|
||||
* were grabbing it, so we don't reach behind us and grab it again as we are trying to
|
||||
* dismount.
|
||||
*/
|
||||
void CCSPlayer::SurpressLadderChecks( const Vector& pos, const Vector& normal )
|
||||
{
|
||||
m_ladderSurpressionTimer.Start( 1.0f );
|
||||
m_lastLadderPos = pos;
|
||||
m_lastLadderNormal = normal;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Prevent us from re-grabbing the same ladder we were just on:
|
||||
* - if the timer is elapsed, let us grab again
|
||||
* - if the normal is different, let us grab
|
||||
* - if the 2D pos is very different, let us grab, since it's probably a different ladder
|
||||
*/
|
||||
bool CCSPlayer::CanGrabLadder( const Vector& pos, const Vector& normal )
|
||||
{
|
||||
if ( m_ladderSurpressionTimer.GetRemainingTime() <= 0.0f )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const float MaxDist = 64.0f;
|
||||
if ( pos.AsVector2D().DistToSqr( m_lastLadderPos.AsVector2D() ) < MaxDist * MaxDist )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( normal != m_lastLadderNormal )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CCSPlayer::SetAnimation( PLAYER_ANIM playerAnim )
|
||||
{
|
||||
// In CS, its CPlayerAnimState object manages ALL the animation state.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
CWeaponCSBase* CCSPlayer::CSAnim_GetActiveWeapon()
|
||||
{
|
||||
return GetActiveCSWeapon();
|
||||
}
|
||||
|
||||
|
||||
bool CCSPlayer::CSAnim_CanMove()
|
||||
{
|
||||
return CanMove();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#define MATERIAL_NAME_LENGTH 16
|
||||
|
||||
#ifdef GAME_DLL
|
||||
|
||||
class CFootstepControl : public CBaseTrigger
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CFootstepControl, CBaseTrigger );
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
virtual int UpdateTransmitState( void );
|
||||
virtual void Spawn( void );
|
||||
|
||||
CNetworkVar( string_t, m_source );
|
||||
CNetworkVar( string_t, m_destination );
|
||||
};
|
||||
|
||||
LINK_ENTITY_TO_CLASS( func_footstep_control, CFootstepControl );
|
||||
|
||||
|
||||
BEGIN_DATADESC( CFootstepControl )
|
||||
DEFINE_KEYFIELD( m_source, FIELD_STRING, "Source" ),
|
||||
DEFINE_KEYFIELD( m_destination, FIELD_STRING, "Destination" ),
|
||||
END_DATADESC()
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( CFootstepControl, DT_FootstepControl )
|
||||
SendPropStringT( SENDINFO(m_source) ),
|
||||
SendPropStringT( SENDINFO(m_destination) ),
|
||||
END_SEND_TABLE()
|
||||
|
||||
int CFootstepControl::UpdateTransmitState( void )
|
||||
{
|
||||
return SetTransmitState( FL_EDICT_ALWAYS );
|
||||
}
|
||||
|
||||
void CFootstepControl::Spawn( void )
|
||||
{
|
||||
InitTrigger();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class C_FootstepControl : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_FootstepControl, C_BaseEntity );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_FootstepControl( void );
|
||||
~C_FootstepControl();
|
||||
|
||||
char m_source[MATERIAL_NAME_LENGTH];
|
||||
char m_destination[MATERIAL_NAME_LENGTH];
|
||||
};
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_FootstepControl, DT_FootstepControl, CFootstepControl)
|
||||
RecvPropString( RECVINFO(m_source) ),
|
||||
RecvPropString( RECVINFO(m_destination) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
CUtlVector< C_FootstepControl * > s_footstepControllers;
|
||||
|
||||
C_FootstepControl::C_FootstepControl( void )
|
||||
{
|
||||
s_footstepControllers.AddToTail( this );
|
||||
}
|
||||
|
||||
C_FootstepControl::~C_FootstepControl()
|
||||
{
|
||||
s_footstepControllers.FindAndRemove( this );
|
||||
}
|
||||
|
||||
surfacedata_t * CCSPlayer::GetFootstepSurface( const Vector &origin, const char *surfaceName )
|
||||
{
|
||||
for ( int i=0; i<s_footstepControllers.Count(); ++i )
|
||||
{
|
||||
C_FootstepControl *control = s_footstepControllers[i];
|
||||
|
||||
if ( FStrEq( control->m_source, surfaceName ) )
|
||||
{
|
||||
if ( control->CollisionProp()->IsPointInBounds( origin ) )
|
||||
{
|
||||
return physprops->GetSurfaceData( physprops->GetSurfaceIndex( control->m_destination ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return physprops->GetSurfaceData( physprops->GetSurfaceIndex( surfaceName ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,82 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TF_PLAYERANIMSTATE_H
|
||||
#define TF_PLAYERANIMSTATE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "convar.h"
|
||||
#include "iplayeranimstate.h"
|
||||
#include "base_playeranimstate.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
class C_BaseAnimatingOverlay;
|
||||
class C_WeaponCSBase;
|
||||
// Avoid redef warnings
|
||||
#undef CBaseAnimatingOverlay
|
||||
#define CBaseAnimatingOverlay C_BaseAnimatingOverlay
|
||||
#define CWeaponCSBase C_WeaponCSBase
|
||||
#define CCSPlayer C_CSPlayer
|
||||
#else
|
||||
class CBaseAnimatingOverlay;
|
||||
class CWeaponCSBase;
|
||||
class CCSPlayer;
|
||||
#endif
|
||||
|
||||
|
||||
// When moving this fast, he plays run anim.
|
||||
#define ARBITRARY_RUN_SPEED 175.0f
|
||||
|
||||
|
||||
enum PlayerAnimEvent_t
|
||||
{
|
||||
PLAYERANIMEVENT_FIRE_GUN_PRIMARY=0,
|
||||
PLAYERANIMEVENT_FIRE_GUN_SECONDARY,
|
||||
PLAYERANIMEVENT_THROW_GRENADE,
|
||||
PLAYERANIMEVENT_JUMP,
|
||||
PLAYERANIMEVENT_RELOAD,
|
||||
PLAYERANIMEVENT_RELOAD_START, ///< w_model partial reload for shotguns
|
||||
PLAYERANIMEVENT_RELOAD_LOOP, ///< w_model partial reload for shotguns
|
||||
PLAYERANIMEVENT_RELOAD_END, ///< w_model partial reload for shotguns
|
||||
PLAYERANIMEVENT_CLEAR_FIRING, ///< clear animations on the firing layer
|
||||
|
||||
PLAYERANIMEVENT_COUNT
|
||||
};
|
||||
|
||||
|
||||
class ICSPlayerAnimState : 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;
|
||||
|
||||
// Returns true if we're playing the grenade prime or throw animation.
|
||||
virtual bool IsThrowingGrenade() = 0;
|
||||
};
|
||||
|
||||
|
||||
// This abstracts the differences between CS players and hostages.
|
||||
class ICSPlayerAnimStateHelpers
|
||||
{
|
||||
public:
|
||||
virtual CWeaponCSBase* CSAnim_GetActiveWeapon() = 0;
|
||||
virtual bool CSAnim_CanMove() = 0;
|
||||
};
|
||||
|
||||
|
||||
ICSPlayerAnimState* CreatePlayerAnimState( CBaseAnimatingOverlay *pEntity, ICSPlayerAnimStateHelpers *pHelpers, LegAnimType_t legAnimType, bool bUseAimSequences );
|
||||
ICSPlayerAnimState* CreateHostageAnimState( CBaseAnimatingOverlay *pEntity, ICSPlayerAnimStateHelpers *pHelpers, LegAnimType_t legAnimType, bool bUseAimSequences );
|
||||
|
||||
// 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 // TF_PLAYERANIMSTATE_H
|
||||
@@ -0,0 +1,67 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "cs_shareddefs.h"
|
||||
|
||||
const float CS_PLAYER_SPEED_RUN = 260.0f;
|
||||
const float CS_PLAYER_SPEED_VIP = 227.0f;
|
||||
const float CS_PLAYER_SPEED_WALK = 100.0f;
|
||||
const float CS_PLAYER_SPEED_SHIELD = 160.0f;
|
||||
const float CS_PLAYER_SPEED_STOPPED = 1.0f;
|
||||
const float CS_PLAYER_SPEED_OBSERVER = 900.0f;
|
||||
|
||||
const float CS_PLAYER_SPEED_DUCK_MODIFIER = 0.34f;
|
||||
const float CS_PLAYER_SPEED_WALK_MODIFIER = 0.52f;
|
||||
const float CS_PLAYER_SPEED_CLIMB_MODIFIER = 0.34f;
|
||||
|
||||
|
||||
CCSClassInfo g_ClassInfos[] =
|
||||
{
|
||||
{ "None" },
|
||||
|
||||
{ "Phoenix Connection" },
|
||||
{ "L337 KREW" },
|
||||
{ "Arctic Avengers" },
|
||||
{ "Guerilla Warfare" },
|
||||
|
||||
{ "Seal Team 6" },
|
||||
{ "GSG-9" },
|
||||
{ "SAS" },
|
||||
{ "GIGN" }
|
||||
};
|
||||
|
||||
const CCSClassInfo* GetCSClassInfo( int i )
|
||||
{
|
||||
Assert( i >= 0 && i < ARRAYSIZE( g_ClassInfos ) );
|
||||
return &g_ClassInfos[i];
|
||||
}
|
||||
|
||||
const char *pszWinPanelCategoryHeaders[] =
|
||||
{
|
||||
"",
|
||||
"#winpanel_topdamage",
|
||||
"#winpanel_topheadshots",
|
||||
"#winpanel_kills"
|
||||
};
|
||||
|
||||
// Construct some arrays of player model strings, so we can statically initialize CUtlVectors for general usage
|
||||
const char *CTPlayerModelStrings[] =
|
||||
{
|
||||
"models/player/ct_urban.mdl",
|
||||
"models/player/ct_gsg9.mdl",
|
||||
"models/player/ct_sas.mdl",
|
||||
"models/player/ct_gign.mdl",
|
||||
};
|
||||
const char *TerroristPlayerModelStrings[] =
|
||||
{
|
||||
"models/player/t_phoenix.mdl",
|
||||
"models/player/t_leet.mdl",
|
||||
"models/player/t_arctic.mdl",
|
||||
"models/player/t_guerilla.mdl",
|
||||
};
|
||||
CUtlVectorInitialized< const char * > CTPlayerModels( CTPlayerModelStrings, ARRAYSIZE( CTPlayerModelStrings ) );
|
||||
CUtlVectorInitialized< const char * > TerroristPlayerModels( TerroristPlayerModelStrings, ARRAYSIZE( TerroristPlayerModelStrings ) );
|
||||
@@ -0,0 +1,261 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Shared CS definitions.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CS_SHAREDDEFS_H
|
||||
#define CS_SHAREDDEFS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
/*======================*/
|
||||
// Menu stuff //
|
||||
/*======================*/
|
||||
|
||||
#include <game/client/iviewport.h>
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// Including Achievement ID Definitions
|
||||
//=============================================================================
|
||||
|
||||
#include "cs_achievementdefs.h"
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
// CS-specific viewport panels
|
||||
#define PANEL_CLASS_CT "class_ct"
|
||||
#define PANEL_CLASS_TER "class_ter"
|
||||
|
||||
// Buy sub menus
|
||||
#define MENU_PISTOL "menu_pistol"
|
||||
#define MENU_SHOTGUN "menu_shotgun"
|
||||
#define MENU_RIFLE "menu_rifle"
|
||||
#define MENU_SMG "menu_smg"
|
||||
#define MENU_MACHINEGUN "menu_mg"
|
||||
#define MENU_EQUIPMENT "menu_equip"
|
||||
|
||||
|
||||
#define MAX_HOSTAGES 12
|
||||
#define MAX_HOSTAGE_RESCUES 4
|
||||
|
||||
|
||||
|
||||
|
||||
#define CSTRIKE_DEFAULT_AVATAR "avatar_default_64"
|
||||
#define CSTRIKE_DEFAULT_T_AVATAR "avatar_default-t_64"
|
||||
#define CSTRIKE_DEFAULT_CT_AVATAR "avatar_default_64"
|
||||
|
||||
extern const float CS_PLAYER_SPEED_RUN;
|
||||
extern const float CS_PLAYER_SPEED_VIP;
|
||||
extern const float CS_PLAYER_SPEED_WALK;
|
||||
extern const float CS_PLAYER_SPEED_SHIELD;
|
||||
extern const float CS_PLAYER_SPEED_STOPPED;
|
||||
extern const float CS_PLAYER_SPEED_OBSERVER;
|
||||
|
||||
extern const float CS_PLAYER_SPEED_DUCK_MODIFIER;
|
||||
extern const float CS_PLAYER_SPEED_WALK_MODIFIER;
|
||||
extern const float CS_PLAYER_SPEED_CLIMB_MODIFIER;
|
||||
|
||||
|
||||
template< class T >
|
||||
class CUtlVectorInitialized : public CUtlVector< T >
|
||||
{
|
||||
public:
|
||||
CUtlVectorInitialized( T* pMemory, int numElements ) : CUtlVector< T >( pMemory, numElements )
|
||||
{
|
||||
this->SetSize( numElements );
|
||||
}
|
||||
};
|
||||
|
||||
extern CUtlVectorInitialized< const char * > CTPlayerModels;
|
||||
extern CUtlVectorInitialized< const char * > TerroristPlayerModels;
|
||||
|
||||
|
||||
// These go in CCSPlayer::m_iAddonBits and get sent to the client so it can create
|
||||
// grenade models hanging off players.
|
||||
#define ADDON_FLASHBANG_1 0x001
|
||||
#define ADDON_FLASHBANG_2 0x002
|
||||
#define ADDON_HE_GRENADE 0x004
|
||||
#define ADDON_SMOKE_GRENADE 0x008
|
||||
#define ADDON_C4 0x010
|
||||
#define ADDON_DEFUSEKIT 0x020
|
||||
#define ADDON_PRIMARY 0x040
|
||||
#define ADDON_PISTOL 0x080
|
||||
#define ADDON_PISTOL2 0x100
|
||||
#define NUM_ADDON_BITS 9
|
||||
|
||||
|
||||
// Indices of each weapon slot.
|
||||
#define WEAPON_SLOT_RIFLE 0 // (primary slot)
|
||||
#define WEAPON_SLOT_PISTOL 1 // (secondary slot)
|
||||
#define WEAPON_SLOT_KNIFE 2
|
||||
#define WEAPON_SLOT_GRENADES 3
|
||||
#define WEAPON_SLOT_C4 4
|
||||
|
||||
#define WEAPON_SLOT_FIRST 0
|
||||
#define WEAPON_SLOT_LAST 4
|
||||
|
||||
|
||||
// CS Team IDs.
|
||||
#define TEAM_TERRORIST 2
|
||||
#define TEAM_CT 3
|
||||
#define TEAM_MAXCOUNT 4 // update this if we ever add teams (unlikely)
|
||||
|
||||
#define MAX_CLAN_TAG_LENGTH 16 // max for new tags is actually 12, this allows some backward compat.
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [menglish] CS specific death animation time now that freeze cam is implemented
|
||||
// in order to linger on the players body less
|
||||
// [tj] The number of times you must kill a given player to be dominating them
|
||||
// [menglish] Flags to use upon player death
|
||||
//=============================================================================
|
||||
|
||||
// [menglish] CS specific death animation time now that freeze cam is implemented
|
||||
// in order to linger on the players body less
|
||||
#define CS_DEATH_ANIMATION_TIME 0.8
|
||||
|
||||
// [tj] The number of times you must kill a given player to be dominating them
|
||||
// Should always be more than 1
|
||||
#define CS_KILLS_FOR_DOMINATION 4
|
||||
|
||||
#define CS_DEATH_DOMINATION 0x0001 // killer is dominating victim
|
||||
#define CS_DEATH_REVENGE 0x0002 // killer got revenge on victim
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
|
||||
//--------------
|
||||
// CSPort Specific damage flags
|
||||
//--------------
|
||||
#define DMG_HEADSHOT (DMG_LASTGENERICFLAG<<1)
|
||||
|
||||
|
||||
// The various states the player can be in during the join game process.
|
||||
enum CSPlayerState
|
||||
{
|
||||
// Happily running around in the game.
|
||||
// You can't move though if CSGameRules()->IsFreezePeriod() returns true.
|
||||
// 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_WAIT_FOR_KEY, // Done playing death anim. Waiting for keypress to go into observer mode.
|
||||
STATE_OBSERVER_MODE, // Noclipping around, watching players, etc.
|
||||
NUM_PLAYER_STATES
|
||||
};
|
||||
|
||||
|
||||
enum e_RoundEndReason
|
||||
{
|
||||
Invalid_Round_End_Reason = -1,
|
||||
Target_Bombed,
|
||||
VIP_Escaped,
|
||||
VIP_Assassinated,
|
||||
Terrorists_Escaped,
|
||||
CTs_PreventEscape,
|
||||
Escaping_Terrorists_Neutralized,
|
||||
Bomb_Defused,
|
||||
CTs_Win,
|
||||
Terrorists_Win,
|
||||
Round_Draw,
|
||||
All_Hostages_Rescued,
|
||||
Target_Saved,
|
||||
Hostages_Not_Rescued,
|
||||
Terrorists_Not_Escaped,
|
||||
VIP_Not_Escaped,
|
||||
Game_Commencing,
|
||||
RoundEndReason_Count
|
||||
};
|
||||
|
||||
#define PUSHAWAY_THINK_INTERVAL (1.0f / 20.0f)
|
||||
|
||||
enum
|
||||
{
|
||||
CS_CLASS_NONE=0,
|
||||
|
||||
// Terrorist classes (keep in sync with FIRST_T_CLASS/LAST_T_CLASS).
|
||||
CS_CLASS_PHOENIX_CONNNECTION,
|
||||
CS_CLASS_L337_KREW,
|
||||
CS_CLASS_ARCTIC_AVENGERS,
|
||||
CS_CLASS_GUERILLA_WARFARE,
|
||||
|
||||
// CT classes (keep in sync with FIRST_CT_CLASS/LAST_CT_CLASS).
|
||||
CS_CLASS_SEAL_TEAM_6,
|
||||
CS_CLASS_GSG_9,
|
||||
CS_CLASS_SAS,
|
||||
CS_CLASS_GIGN,
|
||||
|
||||
CS_NUM_CLASSES
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [menglish] List of equipment dropped by players with freeze panel callouts
|
||||
//=============================================================================
|
||||
enum
|
||||
{
|
||||
DROPPED_C4,
|
||||
DROPPED_DEFUSE,
|
||||
DROPPED_WEAPON,
|
||||
DROPPED_GRENADE, // This could be an HE greande, flashbang, or smoke
|
||||
DROPPED_COUNT
|
||||
};
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// MVP reasons
|
||||
//
|
||||
enum CSMvpReason_t
|
||||
{
|
||||
CSMVP_UNDEFINED = 0,
|
||||
CSMVP_ELIMINATION,
|
||||
CSMVP_BOMBPLANT,
|
||||
CSMVP_BOMBDEFUSE,
|
||||
CSMVP_HOSTAGERESCUE,
|
||||
};
|
||||
|
||||
|
||||
// Keep these in sync with CSClasses.
|
||||
#define FIRST_T_CLASS CS_CLASS_PHOENIX_CONNNECTION
|
||||
#define LAST_T_CLASS CS_CLASS_GUERILLA_WARFARE
|
||||
|
||||
#define FIRST_CT_CLASS CS_CLASS_SEAL_TEAM_6
|
||||
#define LAST_CT_CLASS CS_CLASS_GIGN
|
||||
|
||||
#define CS_MUZZLEFLASH_NONE -1
|
||||
#define CS_MUZZLEFLASH_NORM 0
|
||||
#define CS_MUZZLEFLASH_X 1
|
||||
|
||||
class CCSClassInfo
|
||||
{
|
||||
public:
|
||||
const char *m_pClassName;
|
||||
};
|
||||
|
||||
const CCSClassInfo* GetCSClassInfo( int i );
|
||||
|
||||
extern const char *pszWinPanelCategoryHeaders[];
|
||||
|
||||
#endif // CS_SHAREDDEFS_H
|
||||
@@ -0,0 +1,237 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
//#include "stdafx.h"
|
||||
#ifdef _WIN32
|
||||
#include "winlite.h"
|
||||
#include "winsock.h"
|
||||
#elif POSIX
|
||||
#define INVALID_SOCKET -1
|
||||
#define SOCKET_ERROR -1
|
||||
#define SOCKET int
|
||||
#define LPSOCKADDR struct sockaddr *
|
||||
#define SOCKADDR_IN struct sockaddr_in
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#define closesocket close
|
||||
#endif
|
||||
#include "tier1/strtools.h"
|
||||
#include "KeyValues.h"
|
||||
#include "utlbuffer.h"
|
||||
#include "tier1/checksum_crc.h"
|
||||
#include "tier1/convar.h"
|
||||
#include "cbase.h"
|
||||
#include "cs_gamestats.h"
|
||||
#include "cs_gamerules.h"
|
||||
#include "cs_urlretrieveprices.h"
|
||||
|
||||
#if _DEBUG
|
||||
#define WEEKLY_PRICE_URL "http://gamestats/weeklyprices.dat"
|
||||
#else
|
||||
#define WEEKLY_PRICE_URL "http://www.steampowered.com/stats/csmarket/weeklyprices.dat"
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: request a URL from connection
|
||||
//-----------------------------------------------------------------------------
|
||||
bool SendHTTPRequest( const char *pchRequestURL, SOCKET socketHTML )
|
||||
{
|
||||
char szHeader[ MED_BUFFER_SIZE ];
|
||||
char szHostName[ SMALL_BUFFER_SIZE ];
|
||||
::gethostname( szHostName, sizeof(szHostName) );
|
||||
|
||||
Q_snprintf( szHeader, sizeof(szHeader), "GET %s HTTP/1.0\r\n" \
|
||||
"Accept: */*\r\n" \
|
||||
"Accept-Language: en-us\r\n" \
|
||||
"User-Agent: Steam/3.0\r\n" \
|
||||
"Host: %s\r\n" \
|
||||
"\r\n",
|
||||
pchRequestURL, szHostName );
|
||||
|
||||
return ::send( socketHTML, szHeader, Q_strlen(szHeader) + 1, 0 ) != SOCKET_ERROR ;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Given a previous HTTP request parse the response into a key values buffer
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ParseHTTPResponse( SOCKET socketHTML, uint32 *unPageHash = NULL )
|
||||
{
|
||||
char szHeaderBuf[ MED_BUFFER_SIZE ];
|
||||
char szBodyBuf[ MED_BUFFER_SIZE ];
|
||||
|
||||
int dwRet = 0;
|
||||
bool bFinishedHeaderRead = false;
|
||||
int iRecvPosition = 0;
|
||||
int cCharsInLine = 0;
|
||||
|
||||
// scan for the end of the header
|
||||
while ( !bFinishedHeaderRead && iRecvPosition < sizeof(szHeaderBuf) )
|
||||
{
|
||||
dwRet = ::recv( socketHTML, &szHeaderBuf[ iRecvPosition ] , 1, 0);
|
||||
if ( dwRet < 0 )
|
||||
{
|
||||
bFinishedHeaderRead = true;
|
||||
}
|
||||
|
||||
switch( szHeaderBuf[ iRecvPosition ] )
|
||||
{
|
||||
case '\r':
|
||||
break;
|
||||
case '\n':
|
||||
if ( cCharsInLine == 0 )
|
||||
bFinishedHeaderRead = true;
|
||||
|
||||
cCharsInLine = 0;
|
||||
break;
|
||||
default:
|
||||
cCharsInLine++;
|
||||
break;
|
||||
}
|
||||
|
||||
iRecvPosition++;
|
||||
}
|
||||
|
||||
CUtlBuffer buf;
|
||||
buf.SetBufferType( false, false );
|
||||
while( 1 )
|
||||
{
|
||||
dwRet = ::recv( socketHTML, szBodyBuf, sizeof(szBodyBuf)-1, 0);
|
||||
if ( dwRet <= 0 )
|
||||
break;
|
||||
|
||||
buf.Put( szBodyBuf, sizeof(szBodyBuf)-1 );
|
||||
}
|
||||
|
||||
weeklyprice_t weeklyprice;
|
||||
Q_memset( &weeklyprice, 0, sizeof( weeklyprice_t) );
|
||||
|
||||
buf.Get( &weeklyprice, sizeof( weeklyprice_t ) );
|
||||
|
||||
if ( weeklyprice.iVersion != PRICE_BLOB_VERSION )
|
||||
{
|
||||
Msg( "Incorrect price blob version! Update your server!\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
CSGameRules()->AddPricesToTable( weeklyprice );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Given http url crack it into an address and the request part
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ProcessURL( const char *pchURL, void *pSockAddrIn, char *pchRequest, int cchRequest )
|
||||
{
|
||||
char rgchHost[ MAX_DNS_NAME ];
|
||||
char rgchRequest[ MED_BUFFER_SIZE ];
|
||||
uint16 iPort;
|
||||
|
||||
if ( Q_strnicmp( pchURL, "http://", 7 ) != 0 )
|
||||
{
|
||||
Assert( !"http protocol only supported" );
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *pchColon = strchr( pchURL + 7, ':' );
|
||||
if ( pchColon )
|
||||
{
|
||||
Q_strncpy( rgchHost, pchURL + 7, pchColon - ( pchURL + 7 ) + 1 );
|
||||
const char *pchForwardSlash = strchr( pchColon + 1, '/' );
|
||||
if ( !pchForwardSlash )
|
||||
return false;
|
||||
Q_strncpy( rgchRequest, pchColon + 1, pchForwardSlash - ( pchColon + 1 ) + 1 );
|
||||
iPort = atoi( rgchRequest );
|
||||
Q_strncpy( rgchRequest, pchForwardSlash, ( pchURL + Q_strlen(pchURL) ) - pchForwardSlash + 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *pchForwardSlash = strchr( pchURL + 7, '/' );
|
||||
if ( !pchForwardSlash )
|
||||
return false;
|
||||
|
||||
Q_strncpy( rgchHost, pchURL + 7, pchForwardSlash - ( pchURL + 7 ) + 1 );
|
||||
iPort = 80;
|
||||
Q_strncpy( rgchRequest, pchForwardSlash, ( pchURL + Q_strlen(pchURL) ) - pchForwardSlash + 1 );
|
||||
}
|
||||
|
||||
struct hostent *hp = NULL;
|
||||
if ( inet_addr( rgchHost ) == INADDR_NONE )
|
||||
{
|
||||
hp = gethostbyname( rgchHost );
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 addr = inet_addr( rgchHost );
|
||||
hp = gethostbyaddr( ( char* )&addr, sizeof( addr ), AF_INET );
|
||||
}
|
||||
|
||||
if( hp == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sockaddr_in &sockAddrIn = *((sockaddr_in *)pSockAddrIn);
|
||||
sockAddrIn.sin_addr.s_addr = *( ( unsigned long* )hp->h_addr );
|
||||
sockAddrIn.sin_family = AF_INET;
|
||||
sockAddrIn.sin_port = htons( iPort );
|
||||
|
||||
Q_strncpy( pchRequest, rgchRequest, cchRequest );
|
||||
return true;
|
||||
}
|
||||
|
||||
//networkstringtable
|
||||
|
||||
bool BlackMarket_DownloadPrices( void )
|
||||
{
|
||||
char szRequest[ MED_BUFFER_SIZE ];
|
||||
sockaddr_in server;
|
||||
bool bConnected = false;
|
||||
|
||||
if ( ProcessURL( WEEKLY_PRICE_URL, &server, szRequest, sizeof(szRequest) ) )
|
||||
{
|
||||
SOCKET socketHTML = ::socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
|
||||
if ( socketHTML != INVALID_SOCKET)
|
||||
{
|
||||
int iRet = ::connect( socketHTML, (LPSOCKADDR)&server, sizeof(SOCKADDR_IN) );
|
||||
|
||||
if ( !iRet )
|
||||
{
|
||||
bConnected = true;
|
||||
if ( SendHTTPRequest( szRequest, socketHTML ) )
|
||||
{
|
||||
uint32 unHash = 0;
|
||||
bool bRet = ParseHTTPResponse( socketHTML, &unHash );
|
||||
|
||||
closesocket( socketHTML );
|
||||
|
||||
return bRet;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
closesocket( socketHTML );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef URLRETRIEVETHREAD_H
|
||||
#define URLRETRIEVETHREAD_H
|
||||
|
||||
#include "KeyValues.h"
|
||||
#include "cs_weapon_parse.h"
|
||||
|
||||
bool BlackMarket_DownloadPrices( void );
|
||||
|
||||
#define MED_BUFFER_SIZE 1024
|
||||
#define SMALL_BUFFER_SIZE 255
|
||||
#define MAX_DNS_NAME 255
|
||||
|
||||
#define PRICE_BLOB_VERSION 1
|
||||
#define PRICE_BLOB_NAME "weeklyprices.dat"
|
||||
|
||||
struct weeklyprice_t
|
||||
{
|
||||
short iVersion;
|
||||
short iPreviousPrice[WEAPON_MAX];
|
||||
short iCurrentPrice[WEAPON_MAX];
|
||||
};
|
||||
|
||||
#endif // URLRETRIEVETHREAD_H
|
||||
@@ -0,0 +1,80 @@
|
||||
//========= 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( "SayText2", -1 );
|
||||
usermessages->Register( "TextMsg", -1 );
|
||||
usermessages->Register( "HudMsg", -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( "SendAudio", -1 ); // play radio command
|
||||
usermessages->Register( "RawAudio", -1 ); // play a .wav as a radio command
|
||||
|
||||
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 radio text display
|
||||
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( "AmmoDenied", 2 );
|
||||
usermessages->Register( "UpdateRadar", -1 );
|
||||
usermessages->Register( "KillCam", -1 );
|
||||
usermessages->Register( "MarkAchievement", -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();
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [menglish] Registering PlayerStatsUpdate for Stats implementation
|
||||
// [dwenger] AchievementEvent: Necessary for server-side achievement awarding
|
||||
// [tj] Added support for absolute current match statistics updates
|
||||
//=============================================================================
|
||||
|
||||
usermessages->Register( "PlayerStatsUpdate_DEPRECATED", -1 ); // Protocol changed, this message replaced below
|
||||
usermessages->Register( "AchievementEvent", -1 );
|
||||
usermessages->Register( "MatchEndConditions", -1 ); //The end conditions for the match. long frag limit, long max rounds, long rounds needed won, and long time
|
||||
usermessages->Register( "MatchStatsUpdate", -1 );
|
||||
usermessages->Register( "PlayerStatsUpdate", -1 ); //Processes stats update
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
}
|
||||
@@ -0,0 +1,455 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include <KeyValues.h>
|
||||
#include "cs_weapon_parse.h"
|
||||
#include "cs_shareddefs.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "icvar.h"
|
||||
#include "cs_gamerules.h"
|
||||
#include "cs_blackmarket.h"
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
struct WeaponTypeInfo
|
||||
{
|
||||
CSWeaponType type;
|
||||
const char * name;
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
WeaponTypeInfo s_weaponTypeInfo[] =
|
||||
{
|
||||
{ WEAPONTYPE_KNIFE, "Knife" },
|
||||
{ WEAPONTYPE_PISTOL, "Pistol" },
|
||||
{ WEAPONTYPE_SUBMACHINEGUN, "Submachine Gun" }, // First match is printable
|
||||
{ WEAPONTYPE_SUBMACHINEGUN, "submachinegun" },
|
||||
{ WEAPONTYPE_SUBMACHINEGUN, "smg" },
|
||||
{ WEAPONTYPE_RIFLE, "Rifle" },
|
||||
{ WEAPONTYPE_SHOTGUN, "Shotgun" },
|
||||
{ WEAPONTYPE_SNIPER_RIFLE, "Sniper Rifle" }, // First match is printable
|
||||
{ WEAPONTYPE_SNIPER_RIFLE, "SniperRifle" },
|
||||
{ WEAPONTYPE_MACHINEGUN, "Machine Gun" }, // First match is printable
|
||||
{ WEAPONTYPE_MACHINEGUN, "machinegun" },
|
||||
{ WEAPONTYPE_MACHINEGUN, "mg" },
|
||||
{ WEAPONTYPE_C4, "C4" },
|
||||
{ WEAPONTYPE_GRENADE, "Grenade" },
|
||||
};
|
||||
|
||||
|
||||
struct WeaponNameInfo
|
||||
{
|
||||
CSWeaponID id;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
WeaponNameInfo s_weaponNameInfo[] =
|
||||
{
|
||||
{ WEAPON_P228, "weapon_p228" },
|
||||
{ WEAPON_GLOCK, "weapon_glock" },
|
||||
{ WEAPON_SCOUT, "weapon_scout" },
|
||||
{ WEAPON_HEGRENADE, "weapon_hegrenade" },
|
||||
{ WEAPON_XM1014, "weapon_xm1014" },
|
||||
{ WEAPON_C4, "weapon_c4" },
|
||||
{ WEAPON_MAC10, "weapon_mac10" },
|
||||
{ WEAPON_AUG, "weapon_aug" },
|
||||
{ WEAPON_SMOKEGRENADE, "weapon_smokegrenade" },
|
||||
{ WEAPON_ELITE, "weapon_elite" },
|
||||
{ WEAPON_FIVESEVEN, "weapon_fiveseven" },
|
||||
{ WEAPON_UMP45, "weapon_ump45" },
|
||||
{ WEAPON_SG550, "weapon_sg550" },
|
||||
|
||||
{ WEAPON_GALIL, "weapon_galil" },
|
||||
{ WEAPON_FAMAS, "weapon_famas" },
|
||||
{ WEAPON_USP, "weapon_usp" },
|
||||
{ WEAPON_AWP, "weapon_awp" },
|
||||
{ WEAPON_MP5NAVY, "weapon_mp5navy" },
|
||||
{ WEAPON_M249, "weapon_m249" },
|
||||
{ WEAPON_M3, "weapon_m3" },
|
||||
{ WEAPON_M4A1, "weapon_m4a1" },
|
||||
{ WEAPON_TMP, "weapon_tmp" },
|
||||
{ WEAPON_G3SG1, "weapon_g3sg1" },
|
||||
{ WEAPON_FLASHBANG, "weapon_flashbang" },
|
||||
{ WEAPON_DEAGLE, "weapon_deagle" },
|
||||
{ WEAPON_SG552, "weapon_sg552" },
|
||||
{ WEAPON_AK47, "weapon_ak47" },
|
||||
{ WEAPON_KNIFE, "weapon_knife" },
|
||||
{ WEAPON_P90, "weapon_p90" },
|
||||
|
||||
// not sure any of these are needed
|
||||
{ WEAPON_SHIELDGUN, "weapon_shieldgun" },
|
||||
{ WEAPON_KEVLAR, "weapon_kevlar" },
|
||||
{ WEAPON_ASSAULTSUIT, "weapon_assaultsuit" },
|
||||
{ WEAPON_NVG, "weapon_nvg" },
|
||||
|
||||
{ WEAPON_NONE, "weapon_none" },
|
||||
};
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
CCSWeaponInfo g_EquipmentInfo[MAX_EQUIPMENT];
|
||||
|
||||
void PrepareEquipmentInfo( void )
|
||||
{
|
||||
memset( g_EquipmentInfo, 0, ARRAYSIZE( g_EquipmentInfo ) );
|
||||
|
||||
g_EquipmentInfo[2].SetWeaponPrice( CSGameRules()->GetBlackMarketPriceForWeapon( WEAPON_KEVLAR ) );
|
||||
g_EquipmentInfo[2].SetDefaultPrice( KEVLAR_PRICE );
|
||||
g_EquipmentInfo[2].SetPreviousPrice( CSGameRules()->GetBlackMarketPreviousPriceForWeapon( WEAPON_KEVLAR ) );
|
||||
g_EquipmentInfo[2].m_iTeam = TEAM_UNASSIGNED;
|
||||
Q_strcpy( g_EquipmentInfo[2].szClassName, "weapon_vest" );
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
g_EquipmentInfo[2].iconActive = new CHudTexture;
|
||||
g_EquipmentInfo[2].iconActive->cCharacterInFont = 't';
|
||||
#endif
|
||||
|
||||
g_EquipmentInfo[1].SetWeaponPrice( CSGameRules()->GetBlackMarketPriceForWeapon( WEAPON_ASSAULTSUIT ) );
|
||||
g_EquipmentInfo[1].SetDefaultPrice( ASSAULTSUIT_PRICE );
|
||||
g_EquipmentInfo[1].SetPreviousPrice( CSGameRules()->GetBlackMarketPreviousPriceForWeapon( WEAPON_ASSAULTSUIT ) );
|
||||
g_EquipmentInfo[1].m_iTeam = TEAM_UNASSIGNED;
|
||||
Q_strcpy( g_EquipmentInfo[1].szClassName, "weapon_vesthelm" );
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
g_EquipmentInfo[1].iconActive = new CHudTexture;
|
||||
g_EquipmentInfo[1].iconActive->cCharacterInFont = 'u';
|
||||
#endif
|
||||
|
||||
g_EquipmentInfo[0].SetWeaponPrice( CSGameRules()->GetBlackMarketPriceForWeapon( WEAPON_NVG ) );
|
||||
g_EquipmentInfo[0].SetPreviousPrice( CSGameRules()->GetBlackMarketPreviousPriceForWeapon( WEAPON_NVG ) );
|
||||
g_EquipmentInfo[0].SetDefaultPrice( NVG_PRICE );
|
||||
g_EquipmentInfo[0].m_iTeam = TEAM_UNASSIGNED;
|
||||
Q_strcpy( g_EquipmentInfo[0].szClassName, "weapon_nvgs" );
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
g_EquipmentInfo[0].iconActive = new CHudTexture;
|
||||
g_EquipmentInfo[0].iconActive->cCharacterInFont = 's';
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
CCSWeaponInfo * GetWeaponInfo( CSWeaponID weaponID )
|
||||
{
|
||||
if ( weaponID == WEAPON_NONE )
|
||||
return NULL;
|
||||
|
||||
if ( weaponID >= WEAPON_KEVLAR )
|
||||
{
|
||||
int iIndex = (WEAPON_MAX - weaponID) - 1;
|
||||
|
||||
return &g_EquipmentInfo[iIndex];
|
||||
|
||||
}
|
||||
|
||||
const char *weaponName = WeaponIdAsString(weaponID);
|
||||
WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( weaponName );
|
||||
if ( hWpnInfo == GetInvalidWeaponInfoHandle() )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CCSWeaponInfo *pWeaponInfo = dynamic_cast< CCSWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
|
||||
|
||||
return pWeaponInfo;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
const char* WeaponClassAsString( CSWeaponType weaponType )
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE(s_weaponTypeInfo); ++i )
|
||||
{
|
||||
if ( s_weaponTypeInfo[i].type == weaponType )
|
||||
{
|
||||
return s_weaponTypeInfo[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
CSWeaponType WeaponClassFromString( const char* weaponType )
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE(s_weaponTypeInfo); ++i )
|
||||
{
|
||||
if ( !Q_stricmp( s_weaponTypeInfo[i].name, weaponType ) )
|
||||
{
|
||||
return s_weaponTypeInfo[i].type;
|
||||
}
|
||||
}
|
||||
|
||||
return WEAPONTYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
CSWeaponType WeaponClassFromWeaponID( CSWeaponID weaponID )
|
||||
{
|
||||
const char *weaponStr = WeaponIDToAlias( weaponID );
|
||||
const char *translatedAlias = GetTranslatedWeaponAlias( weaponStr );
|
||||
|
||||
char wpnName[128];
|
||||
Q_snprintf( wpnName, sizeof( wpnName ), "weapon_%s", translatedAlias );
|
||||
WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( wpnName );
|
||||
if ( hWpnInfo != GetInvalidWeaponInfoHandle() )
|
||||
{
|
||||
CCSWeaponInfo *pWeaponInfo = dynamic_cast< CCSWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
|
||||
if ( pWeaponInfo )
|
||||
{
|
||||
return pWeaponInfo->m_WeaponType;
|
||||
}
|
||||
}
|
||||
|
||||
return WEAPONTYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
const char * WeaponIdAsString( CSWeaponID weaponID )
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE(s_weaponNameInfo); ++i )
|
||||
{
|
||||
if (s_weaponNameInfo[i].id == weaponID )
|
||||
return s_weaponNameInfo[i].name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
CSWeaponID WeaponIdFromString( const char *szWeaponName )
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE(s_weaponNameInfo); ++i )
|
||||
{
|
||||
if ( Q_stricmp(s_weaponNameInfo[i].name, szWeaponName) == 0 )
|
||||
return s_weaponNameInfo[i].id;
|
||||
}
|
||||
|
||||
return WEAPON_NONE;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
void ParseVector( KeyValues *keyValues, const char *keyName, Vector& vec )
|
||||
{
|
||||
vec.x = vec.y = vec.z = 0.0f;
|
||||
|
||||
if ( !keyValues || !keyName )
|
||||
return;
|
||||
|
||||
const char *vecString = keyValues->GetString( keyName, "0 0 0" );
|
||||
if ( vecString && *vecString )
|
||||
{
|
||||
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||
if ( 3 == sscanf( vecString, "%f %f %f", &x, &y, &z ) )
|
||||
{
|
||||
vec.x = x;
|
||||
vec.y = y;
|
||||
vec.z = z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FileWeaponInfo_t* CreateWeaponInfo()
|
||||
{
|
||||
return new CCSWeaponInfo;
|
||||
}
|
||||
|
||||
|
||||
CCSWeaponInfo::CCSWeaponInfo()
|
||||
{
|
||||
m_flMaxSpeed = 1; // This should always be set in the script.
|
||||
m_szAddonModel[0] = 0;
|
||||
}
|
||||
|
||||
int CCSWeaponInfo::GetWeaponPrice( void ) const
|
||||
{
|
||||
return m_iWeaponPrice;
|
||||
}
|
||||
|
||||
int CCSWeaponInfo::GetDefaultPrice( void )
|
||||
{
|
||||
return m_iDefaultPrice;
|
||||
}
|
||||
|
||||
int CCSWeaponInfo::GetPrevousPrice( void )
|
||||
{
|
||||
return m_iPreviousPrice;
|
||||
}
|
||||
|
||||
|
||||
void CCSWeaponInfo::Parse( KeyValues *pKeyValuesData, const char *szWeaponName )
|
||||
{
|
||||
BaseClass::Parse( pKeyValuesData, szWeaponName );
|
||||
|
||||
m_flMaxSpeed = (float)pKeyValuesData->GetInt( "MaxPlayerSpeed", 1 );
|
||||
|
||||
m_iDefaultPrice = m_iWeaponPrice = pKeyValuesData->GetInt( "WeaponPrice", -1 );
|
||||
if ( m_iWeaponPrice == -1 )
|
||||
{
|
||||
// This weapon should have the price in its script.
|
||||
Assert( false );
|
||||
}
|
||||
|
||||
if ( CSGameRules()->IsBlackMarket() )
|
||||
{
|
||||
CSWeaponID iWeaponID = AliasToWeaponID( GetTranslatedWeaponAlias ( szWeaponName ) );
|
||||
|
||||
m_iDefaultPrice = m_iWeaponPrice;
|
||||
m_iPreviousPrice = CSGameRules()->GetBlackMarketPreviousPriceForWeapon( iWeaponID );
|
||||
m_iWeaponPrice = CSGameRules()->GetBlackMarketPriceForWeapon( iWeaponID );
|
||||
}
|
||||
|
||||
m_flArmorRatio = pKeyValuesData->GetFloat( "WeaponArmorRatio", 1 );
|
||||
m_iCrosshairMinDistance = pKeyValuesData->GetInt( "CrosshairMinDistance", 4 );
|
||||
m_iCrosshairDeltaDistance = pKeyValuesData->GetInt( "CrosshairDeltaDistance", 3 );
|
||||
m_bCanUseWithShield = !!pKeyValuesData->GetInt( "CanEquipWithShield", false );
|
||||
m_flMuzzleScale = pKeyValuesData->GetFloat( "MuzzleFlashScale", 1 );
|
||||
|
||||
const char *pMuzzleFlashStyle = pKeyValuesData->GetString( "MuzzleFlashStyle", "CS_MUZZLEFLASH_NORM" );
|
||||
|
||||
if( pMuzzleFlashStyle )
|
||||
{
|
||||
if ( Q_stricmp( pMuzzleFlashStyle, "CS_MUZZLEFLASH_X" ) == 0 )
|
||||
{
|
||||
m_iMuzzleFlashStyle = CS_MUZZLEFLASH_X;
|
||||
}
|
||||
else if ( Q_stricmp( pMuzzleFlashStyle, "CS_MUZZLEFLASH_NONE" ) == 0 )
|
||||
{
|
||||
m_iMuzzleFlashStyle = CS_MUZZLEFLASH_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iMuzzleFlashStyle = CS_MUZZLEFLASH_NORM;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( false );
|
||||
}
|
||||
|
||||
m_iPenetration = pKeyValuesData->GetInt( "Penetration", 1 );
|
||||
m_iDamage = pKeyValuesData->GetInt( "Damage", 42 ); // Douglas Adams 1952 - 2001
|
||||
m_flRange = pKeyValuesData->GetFloat( "Range", 8192.0f );
|
||||
m_flRangeModifier = pKeyValuesData->GetFloat( "RangeModifier", 0.98f );
|
||||
m_iBullets = pKeyValuesData->GetInt( "Bullets", 1 );
|
||||
m_flCycleTime = pKeyValuesData->GetFloat( "CycleTime", 0.15 );
|
||||
m_bAccuracyQuadratic= pKeyValuesData->GetInt( "AccuracyQuadratic", 0 );
|
||||
m_flAccuracyDivisor = pKeyValuesData->GetFloat( "AccuracyDivisor", -1 ); // -1 = off
|
||||
m_flAccuracyOffset = pKeyValuesData->GetFloat( "AccuracyOffset", 0 );
|
||||
m_flMaxInaccuracy = pKeyValuesData->GetFloat( "MaxInaccuracy", 0 );
|
||||
|
||||
// new accuracy model parameters
|
||||
m_fSpread[0] = pKeyValuesData->GetFloat("Spread", 0.0f);
|
||||
m_fInaccuracyCrouch[0] = pKeyValuesData->GetFloat("InaccuracyCrouch", 0.0f);
|
||||
m_fInaccuracyStand[0] = pKeyValuesData->GetFloat("InaccuracyStand", 0.0f);
|
||||
m_fInaccuracyJump[0] = pKeyValuesData->GetFloat("InaccuracyJump", 0.0f);
|
||||
m_fInaccuracyLand[0] = pKeyValuesData->GetFloat("InaccuracyLand", 0.0f);
|
||||
m_fInaccuracyLadder[0] = pKeyValuesData->GetFloat("InaccuracyLadder", 0.0f);
|
||||
m_fInaccuracyImpulseFire[0] = pKeyValuesData->GetFloat("InaccuracyFire", 0.0f);
|
||||
m_fInaccuracyMove[0] = pKeyValuesData->GetFloat("InaccuracyMove", 0.0f);
|
||||
|
||||
m_fSpread[1] = pKeyValuesData->GetFloat("SpreadAlt", 0.0f);
|
||||
m_fInaccuracyCrouch[1] = pKeyValuesData->GetFloat("InaccuracyCrouchAlt", 0.0f);
|
||||
m_fInaccuracyStand[1] = pKeyValuesData->GetFloat("InaccuracyStandAlt", 0.0f);
|
||||
m_fInaccuracyJump[1] = pKeyValuesData->GetFloat("InaccuracyJumpAlt", 0.0f);
|
||||
m_fInaccuracyLand[1] = pKeyValuesData->GetFloat("InaccuracyLandAlt", 0.0f);
|
||||
m_fInaccuracyLadder[1] = pKeyValuesData->GetFloat("InaccuracyLadderAlt", 0.0f);
|
||||
m_fInaccuracyImpulseFire[1] = pKeyValuesData->GetFloat("InaccuracyFireAlt", 0.0f);
|
||||
m_fInaccuracyMove[1] = pKeyValuesData->GetFloat("InaccuracyMoveAlt", 0.0f);
|
||||
|
||||
m_fInaccuracyReload = pKeyValuesData->GetFloat("InaccuracyReload", 0.0f);
|
||||
m_fInaccuracyAltSwitch = pKeyValuesData->GetFloat("InaccuracyAltSwitch", 0.0f);
|
||||
|
||||
m_fRecoveryTimeCrouch = pKeyValuesData->GetFloat("RecoveryTimeCrouch", 1.0f);
|
||||
m_fRecoveryTimeStand = pKeyValuesData->GetFloat("RecoveryTimeStand", 1.0f);
|
||||
|
||||
m_flTimeToIdleAfterFire = pKeyValuesData->GetFloat( "TimeToIdle", 2 );
|
||||
m_flIdleInterval = pKeyValuesData->GetFloat( "IdleInterval", 20 );
|
||||
|
||||
// Figure out what team can have this weapon.
|
||||
m_iTeam = TEAM_UNASSIGNED;
|
||||
const char *pTeam = pKeyValuesData->GetString( "Team", NULL );
|
||||
if ( pTeam )
|
||||
{
|
||||
if ( Q_stricmp( pTeam, "CT" ) == 0 )
|
||||
{
|
||||
m_iTeam = TEAM_CT;
|
||||
}
|
||||
else if ( Q_stricmp( pTeam, "TERRORIST" ) == 0 )
|
||||
{
|
||||
m_iTeam = TEAM_TERRORIST;
|
||||
}
|
||||
else if ( Q_stricmp( pTeam, "ANY" ) == 0 )
|
||||
{
|
||||
m_iTeam = TEAM_UNASSIGNED;
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( false );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( false );
|
||||
}
|
||||
|
||||
|
||||
const char *pWrongTeamMsg = pKeyValuesData->GetString( "WrongTeamMsg", "" );
|
||||
Q_strncpy( m_WrongTeamMsg, pWrongTeamMsg, sizeof( m_WrongTeamMsg ) );
|
||||
|
||||
const char *pShieldViewModel = pKeyValuesData->GetString( "shieldviewmodel", "" );
|
||||
Q_strncpy( m_szShieldViewModel, pShieldViewModel, sizeof( m_szShieldViewModel ) );
|
||||
|
||||
const char *pAnimEx = pKeyValuesData->GetString( "PlayerAnimationExtension", "m4" );
|
||||
Q_strncpy( m_szAnimExtension, pAnimEx, sizeof( m_szAnimExtension ) );
|
||||
|
||||
// Default is 2000.
|
||||
m_flBotAudibleRange = pKeyValuesData->GetFloat( "BotAudibleRange", 2000.0f );
|
||||
|
||||
const char *pTypeString = pKeyValuesData->GetString( "WeaponType", "" );
|
||||
m_WeaponType = WeaponClassFromString(pTypeString);
|
||||
|
||||
m_bFullAuto = pKeyValuesData->GetBool("FullAuto");
|
||||
|
||||
// Read the addon model.
|
||||
Q_strncpy( m_szAddonModel, pKeyValuesData->GetString( "AddonModel" ), sizeof( m_szAddonModel ) );
|
||||
|
||||
// Read the dropped model.
|
||||
Q_strncpy( m_szDroppedModel, pKeyValuesData->GetString( "DroppedModel" ), sizeof( m_szDroppedModel ) );
|
||||
|
||||
// Read the silencer model.
|
||||
Q_strncpy( m_szSilencerModel, pKeyValuesData->GetString( "SilencerModel" ), sizeof( m_szSilencerModel ) );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// Enforce consistency for the weapon here, since that way we don't need to save off the model bounds
|
||||
// for all time.
|
||||
// Moved to pure_server_minimal.txt
|
||||
// engine->ForceExactFile( UTIL_VarArgs("scripts/%s.ctx", szWeaponName ) );
|
||||
|
||||
// Model bounds are rounded to the nearest integer, then extended by 1
|
||||
engine->ForceModelBounds( szWorldModel, Vector( -15, -12, -18 ), Vector( 44, 16, 19 ) );
|
||||
if ( m_szAddonModel[0] )
|
||||
{
|
||||
engine->ForceModelBounds( m_szAddonModel, Vector( -5, -5, -6 ), Vector( 13, 5, 7 ) );
|
||||
}
|
||||
if ( m_szSilencerModel[0] )
|
||||
{
|
||||
engine->ForceModelBounds( m_szSilencerModel, Vector( -15, -12, -18 ), Vector( 44, 16, 19 ) );
|
||||
}
|
||||
#endif // !CLIENT_DLL
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CS_WEAPON_PARSE_H
|
||||
#define CS_WEAPON_PARSE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "weapon_parse.h"
|
||||
#include "networkvar.h"
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
enum CSWeaponType
|
||||
{
|
||||
WEAPONTYPE_KNIFE=0,
|
||||
WEAPONTYPE_PISTOL,
|
||||
WEAPONTYPE_SUBMACHINEGUN,
|
||||
WEAPONTYPE_RIFLE,
|
||||
WEAPONTYPE_SHOTGUN,
|
||||
WEAPONTYPE_SNIPER_RIFLE,
|
||||
WEAPONTYPE_MACHINEGUN,
|
||||
WEAPONTYPE_C4,
|
||||
WEAPONTYPE_GRENADE,
|
||||
WEAPONTYPE_UNKNOWN
|
||||
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
enum CSWeaponID
|
||||
{
|
||||
WEAPON_NONE = 0,
|
||||
|
||||
WEAPON_P228,
|
||||
WEAPON_GLOCK,
|
||||
WEAPON_SCOUT,
|
||||
WEAPON_HEGRENADE,
|
||||
WEAPON_XM1014,
|
||||
WEAPON_C4,
|
||||
WEAPON_MAC10,
|
||||
WEAPON_AUG,
|
||||
WEAPON_SMOKEGRENADE,
|
||||
WEAPON_ELITE,
|
||||
WEAPON_FIVESEVEN,
|
||||
WEAPON_UMP45,
|
||||
WEAPON_SG550,
|
||||
|
||||
WEAPON_GALIL,
|
||||
WEAPON_FAMAS,
|
||||
WEAPON_USP,
|
||||
WEAPON_AWP,
|
||||
WEAPON_MP5NAVY,
|
||||
WEAPON_M249,
|
||||
WEAPON_M3,
|
||||
WEAPON_M4A1,
|
||||
WEAPON_TMP,
|
||||
WEAPON_G3SG1,
|
||||
WEAPON_FLASHBANG,
|
||||
WEAPON_DEAGLE,
|
||||
WEAPON_SG552,
|
||||
WEAPON_AK47,
|
||||
WEAPON_KNIFE,
|
||||
WEAPON_P90,
|
||||
|
||||
WEAPON_SHIELDGUN, // BOTPORT: Is this still needed?
|
||||
|
||||
WEAPON_KEVLAR,
|
||||
WEAPON_ASSAULTSUIT,
|
||||
WEAPON_NVG,
|
||||
|
||||
WEAPON_MAX, // number of weapons weapon index
|
||||
};
|
||||
|
||||
#define MAX_EQUIPMENT (WEAPON_MAX - WEAPON_KEVLAR)
|
||||
|
||||
void PrepareEquipmentInfo( void );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
const char * WeaponClassAsString( CSWeaponType weaponType );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
CSWeaponType WeaponClassFromString( const char* weaponType );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
CSWeaponType WeaponClassFromWeaponID( CSWeaponID weaponID );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
const char * WeaponIdAsString( CSWeaponID weaponID );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
CSWeaponID WeaponIdFromString( const char *szWeaponName );
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
class CCSWeaponInfo : public FileWeaponInfo_t
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS_GAMEROOT( CCSWeaponInfo, FileWeaponInfo_t );
|
||||
|
||||
CCSWeaponInfo();
|
||||
|
||||
virtual void Parse( ::KeyValues *pKeyValuesData, const char *szWeaponName );
|
||||
|
||||
int GetRealWeaponPrice( void ) { return m_iWeaponPrice; }
|
||||
|
||||
|
||||
public:
|
||||
|
||||
float m_flMaxSpeed; // How fast the player can run while this is his primary weapon.
|
||||
|
||||
CSWeaponType m_WeaponType;
|
||||
|
||||
bool m_bFullAuto; // is this a fully automatic weapon?
|
||||
|
||||
int m_iTeam; // Which team can have this weapon. TEAM_UNASSIGNED if both can have it.
|
||||
float m_flBotAudibleRange; // How far away a bot can hear this weapon.
|
||||
float m_flArmorRatio;
|
||||
|
||||
int m_iCrosshairMinDistance;
|
||||
int m_iCrosshairDeltaDistance;
|
||||
|
||||
bool m_bCanUseWithShield;
|
||||
|
||||
char m_WrongTeamMsg[32]; // Reference to a string describing the error if someone tries to buy
|
||||
// this weapon but they're on the wrong team to have it.
|
||||
// Zero-length if no specific message for this weapon.
|
||||
|
||||
char m_szAnimExtension[16];
|
||||
char m_szShieldViewModel[64];
|
||||
|
||||
char m_szAddonModel[MAX_WEAPON_STRING]; // If this is set, it is used as the addon model. Otherwise, szWorldModel is used.
|
||||
char m_szDroppedModel[MAX_WEAPON_STRING]; // Alternate dropped model, if different from the szWorldModel the player holds
|
||||
char m_szSilencerModel[MAX_WEAPON_STRING]; // Alternate model with silencer attached
|
||||
|
||||
int m_iMuzzleFlashStyle;
|
||||
float m_flMuzzleScale;
|
||||
|
||||
// Parameters for FX_FireBullets:
|
||||
int m_iPenetration;
|
||||
int m_iDamage;
|
||||
float m_flRange;
|
||||
float m_flRangeModifier;
|
||||
int m_iBullets;
|
||||
float m_flCycleTime;
|
||||
|
||||
// Variables that control how fast the weapon's accuracy changes as it is fired.
|
||||
bool m_bAccuracyQuadratic;
|
||||
float m_flAccuracyDivisor;
|
||||
float m_flAccuracyOffset;
|
||||
float m_flMaxInaccuracy;
|
||||
|
||||
// variables for new accuracy model
|
||||
float m_fSpread[2];
|
||||
float m_fInaccuracyCrouch[2];
|
||||
float m_fInaccuracyStand[2];
|
||||
float m_fInaccuracyJump[2];
|
||||
float m_fInaccuracyLand[2];
|
||||
float m_fInaccuracyLadder[2];
|
||||
float m_fInaccuracyImpulseFire[2];
|
||||
float m_fInaccuracyMove[2];
|
||||
float m_fRecoveryTimeStand;
|
||||
float m_fRecoveryTimeCrouch;
|
||||
float m_fInaccuracyReload;
|
||||
float m_fInaccuracyAltSwitch;
|
||||
|
||||
// Delay until the next idle animation after shooting.
|
||||
float m_flTimeToIdleAfterFire;
|
||||
float m_flIdleInterval;
|
||||
|
||||
int GetWeaponPrice( void ) const;
|
||||
int GetDefaultPrice( void );
|
||||
int GetPrevousPrice( void );
|
||||
void SetWeaponPrice( int iPrice ) { m_iWeaponPrice = iPrice; }
|
||||
void SetDefaultPrice( int iPrice ) { m_iDefaultPrice = iPrice; }
|
||||
void SetPreviousPrice( int iPrice ) { m_iPreviousPrice = iPrice; }
|
||||
|
||||
private:
|
||||
|
||||
int m_iWeaponPrice;
|
||||
int m_iDefaultPrice;
|
||||
int m_iPreviousPrice;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // CS_WEAPON_PARSE_H
|
||||
@@ -0,0 +1,316 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "flashbang_projectile.h"
|
||||
#include "shake.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "cs_player.h"
|
||||
#include "dlight.h"
|
||||
#include "KeyValues.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "collisionutils.h"
|
||||
#include "particle_smokegrenade.h"
|
||||
#include "smoke_fog_overlay_shared.h"
|
||||
|
||||
#define GRENADE_MODEL "models/Weapons/w_eq_flashbang_thrown.mdl"
|
||||
|
||||
|
||||
LINK_ENTITY_TO_CLASS( flashbang_projectile, CFlashbangProjectile );
|
||||
PRECACHE_WEAPON_REGISTER( flashbang_projectile );
|
||||
|
||||
float PercentageOfFlashForPlayer(CBaseEntity *player, Vector flashPos, CBaseEntity *pevInflictor)
|
||||
{
|
||||
float retval = 0.0f;
|
||||
|
||||
trace_t tr;
|
||||
|
||||
Vector pos = player->EyePosition();
|
||||
Vector vecRight, vecUp, vecForward;
|
||||
AngleVectors( player->EyeAngles(), &vecForward );
|
||||
|
||||
QAngle tempAngle;
|
||||
VectorAngles(player->EyePosition() - flashPos, tempAngle);
|
||||
AngleVectors(tempAngle, NULL, &vecRight, &vecUp);
|
||||
|
||||
vecRight.NormalizeInPlace();
|
||||
vecUp.NormalizeInPlace();
|
||||
|
||||
UTIL_TraceLine( flashPos, pos,
|
||||
(CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_DEBRIS|CONTENTS_MONSTER),
|
||||
pevInflictor, COLLISION_GROUP_NONE, &tr );
|
||||
|
||||
if ((tr.fraction == 1.0) || (tr.m_pEnt == player))
|
||||
{
|
||||
retval = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
CBaseEntity *pSGren;
|
||||
|
||||
for( pSGren = gEntList.FindEntityByClassname( NULL, "env_particlesmokegrenade" );
|
||||
pSGren;
|
||||
pSGren = gEntList.FindEntityByClassname( pSGren, "env_particlesmokegrenade" ) )
|
||||
{
|
||||
ParticleSmokeGrenade *pPSG =( ParticleSmokeGrenade* ) pSGren;
|
||||
|
||||
if ( gpGlobals->curtime > pPSG->m_flSpawnTime + pPSG->m_FadeStartTime ) // ignore the smoke grenade if it's fading.
|
||||
continue;
|
||||
|
||||
float flHit1, flHit2;
|
||||
|
||||
float flInnerRadius = SMOKEGRENADE_PARTICLERADIUS;
|
||||
// float flOutterRadius = flInnerRadius + ( 0.5 * SMOKEPARTICLE_SIZE );
|
||||
|
||||
Vector vPos = pSGren->GetAbsOrigin();
|
||||
|
||||
/*debugoverlay->AddBoxOverlay( pSGren->GetAbsOrigin(), Vector( flInnerRadius, flInnerRadius, flInnerRadius ),
|
||||
Vector( -flInnerRadius, -flInnerRadius, -flInnerRadius ), QAngle( 0, 0, 0 ), 0, 255, 0, 30, 10 );
|
||||
debugoverlay->AddBoxOverlay( pSGren->GetAbsOrigin(), Vector( flOutterRadius, flOutterRadius, flOutterRadius ),
|
||||
Vector( -flOutterRadius, -flOutterRadius, -flOutterRadius ), QAngle( 0, 0, 0 ), 255, 0, 0, 30, 10 ); */
|
||||
|
||||
if ( IntersectInfiniteRayWithSphere( pos, vecForward, vPos, flInnerRadius, &flHit1, &flHit2 ) )
|
||||
{
|
||||
retval *= 0.8;
|
||||
}
|
||||
/* else if ( IntersectInfiniteRayWithSphere( pos, vecForward, vPos, flOutterRadius, &flHit1, &flHit2 ) )
|
||||
{
|
||||
retval *= 0.9;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------- //
|
||||
//
|
||||
// RadiusDamage - this entity is exploding, or otherwise needs to inflict damage upon entities within a certain range.
|
||||
//
|
||||
// only damage ents that can clearly be seen by the explosion!
|
||||
// --------------------------------------------------------------------------------------------------- //
|
||||
|
||||
void RadiusFlash(
|
||||
Vector vecSrc,
|
||||
CBaseEntity *pevInflictor,
|
||||
CBaseEntity *pevAttacker,
|
||||
float flDamage,
|
||||
int iClassIgnore,
|
||||
int bitsDamageType )
|
||||
{
|
||||
vecSrc.z += 1;// in case grenade is lying on the ground
|
||||
|
||||
if ( !pevAttacker )
|
||||
pevAttacker = pevInflictor;
|
||||
|
||||
trace_t tr;
|
||||
float flAdjustedDamage;
|
||||
variant_t var;
|
||||
Vector vecEyePos;
|
||||
float fadeTime, fadeHold;
|
||||
Vector vForward;
|
||||
Vector vecLOS;
|
||||
float flDot;
|
||||
|
||||
CBaseEntity *pEntity = NULL;
|
||||
static float flRadius = 1500;
|
||||
float falloff = flDamage / flRadius;
|
||||
|
||||
bool bInWater = (UTIL_PointContents( vecSrc ) == CONTENTS_WATER);
|
||||
|
||||
// iterate on all entities in the vicinity.
|
||||
while ((pEntity = gEntList.FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL)
|
||||
{
|
||||
bool bPlayer = pEntity->IsPlayer();
|
||||
bool bHostage = ( Q_stricmp( pEntity->GetClassname(), "hostage_entity" ) == 0 );
|
||||
|
||||
if( !bPlayer && !bHostage )
|
||||
continue;
|
||||
|
||||
vecEyePos = pEntity->EyePosition();
|
||||
|
||||
// blasts don't travel into or out of water
|
||||
if ( bInWater && pEntity->GetWaterLevel() == 0)
|
||||
continue;
|
||||
if (!bInWater && pEntity->GetWaterLevel() == 3)
|
||||
continue;
|
||||
|
||||
float percentageOfFlash = PercentageOfFlashForPlayer(pEntity, vecSrc, pevInflictor);
|
||||
|
||||
if ( percentageOfFlash > 0.0 )
|
||||
{
|
||||
// decrease damage for an ent that's farther from the grenade
|
||||
flAdjustedDamage = flDamage - ( vecSrc - pEntity->EyePosition() ).Length() * falloff;
|
||||
|
||||
if ( flAdjustedDamage > 0 )
|
||||
{
|
||||
// See if we were facing the flash
|
||||
AngleVectors( pEntity->EyeAngles(), &vForward );
|
||||
|
||||
vecLOS = ( vecSrc - vecEyePos );
|
||||
|
||||
float flDistance = vecLOS.Length();
|
||||
|
||||
// Normalize both vectors so the dotproduct is in the range -1.0 <= x <= 1.0
|
||||
vecLOS.NormalizeInPlace();
|
||||
|
||||
flDot = DotProduct (vecLOS, vForward);
|
||||
|
||||
float startingAlpha = 255;
|
||||
|
||||
// if target is facing the bomb, the effect lasts longer
|
||||
if( flDot >= 0.5 )
|
||||
{
|
||||
// looking at the flashbang
|
||||
fadeTime = flAdjustedDamage * 2.5f;
|
||||
fadeHold = flAdjustedDamage * 1.25f;
|
||||
}
|
||||
else if( flDot >= -0.5 )
|
||||
{
|
||||
// looking to the side
|
||||
fadeTime = flAdjustedDamage * 1.75f;
|
||||
fadeHold = flAdjustedDamage * 0.8f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// facing away
|
||||
fadeTime = flAdjustedDamage * 1.0f;
|
||||
fadeHold = flAdjustedDamage * 0.75f;
|
||||
startingAlpha = 200;
|
||||
}
|
||||
|
||||
fadeTime *= percentageOfFlash;
|
||||
fadeHold *= percentageOfFlash;
|
||||
|
||||
if ( bPlayer )
|
||||
{
|
||||
// blind players and bots
|
||||
CCSPlayer *player = static_cast< CCSPlayer * >( pEntity );
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [tj] Store who was responsible for the most recent flashbang blinding.
|
||||
//=============================================================================
|
||||
|
||||
CCSPlayer *attacker = ToCSPlayer (pevAttacker);
|
||||
if (attacker && player)
|
||||
{
|
||||
player->SetLastFlashbangAttacker(attacker);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
|
||||
|
||||
player->Blind( fadeHold, fadeTime, startingAlpha );
|
||||
|
||||
// deafen players and bots
|
||||
player->Deafen( flDistance );
|
||||
}
|
||||
else if ( bHostage )
|
||||
{
|
||||
variant_t val;
|
||||
val.SetFloat( fadeTime );
|
||||
pEntity->AcceptInput( "flashbang", pevInflictor, pevAttacker, val, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CPVSFilter filter(vecSrc);
|
||||
te->DynamicLight( filter, 0.0, &vecSrc, 255, 255, 255, 2, 400, 0.1, 768 );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------- //
|
||||
// CFlashbangProjectile implementation.
|
||||
// --------------------------------------------------------------------------------------------------- //
|
||||
|
||||
CFlashbangProjectile* CFlashbangProjectile::Create(
|
||||
const Vector &position,
|
||||
const QAngle &angles,
|
||||
const Vector &velocity,
|
||||
const AngularImpulse &angVelocity,
|
||||
CBaseCombatCharacter *pOwner )
|
||||
{
|
||||
CFlashbangProjectile *pGrenade = (CFlashbangProjectile*)CBaseEntity::Create( "flashbang_projectile", position, angles, pOwner );
|
||||
|
||||
// Set the timer for 1 second less than requested. We're going to issue a SOUND_DANGER
|
||||
// one second before detonation.
|
||||
pGrenade->SetAbsVelocity( velocity );
|
||||
pGrenade->SetupInitialTransmittedGrenadeVelocity( velocity );
|
||||
pGrenade->SetThrower( pOwner );
|
||||
pGrenade->m_flDamage = 100;
|
||||
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
|
||||
|
||||
pGrenade->SetTouch( &CBaseGrenade::BounceTouch );
|
||||
|
||||
pGrenade->SetThink( &CBaseCSGrenadeProjectile::DangerSoundThink );
|
||||
pGrenade->SetNextThink( gpGlobals->curtime );
|
||||
|
||||
pGrenade->SetDetonateTimerLength( 1.5 );
|
||||
|
||||
pGrenade->ApplyLocalAngularVelocityImpulse( angVelocity );
|
||||
|
||||
pGrenade->SetGravity( BaseClass::GetGrenadeGravity() );
|
||||
pGrenade->SetFriction( BaseClass::GetGrenadeFriction() );
|
||||
pGrenade->SetElasticity( BaseClass::GetGrenadeElasticity() );
|
||||
|
||||
pGrenade->m_pWeaponInfo = GetWeaponInfo( WEAPON_FLASHBANG );
|
||||
|
||||
|
||||
return pGrenade;
|
||||
}
|
||||
|
||||
void CFlashbangProjectile::Spawn()
|
||||
{
|
||||
SetModel( GRENADE_MODEL );
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
void CFlashbangProjectile::Precache()
|
||||
{
|
||||
PrecacheModel( GRENADE_MODEL );
|
||||
|
||||
PrecacheScriptSound( "Flashbang.Explode" );
|
||||
PrecacheScriptSound( "Flashbang.Bounce" );
|
||||
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
void CFlashbangProjectile::Detonate()
|
||||
{
|
||||
RadiusFlash ( GetAbsOrigin(), this, GetThrower(), 4, CLASS_NONE, DMG_BLAST );
|
||||
EmitSound( "Flashbang.Explode" );
|
||||
|
||||
// tell the bots a flashbang grenade has exploded
|
||||
CCSPlayer *player = ToCSPlayer(GetThrower());
|
||||
if ( player )
|
||||
{
|
||||
IGameEvent * event = gameeventmanager->CreateEvent( "flashbang_detonate" );
|
||||
if ( event )
|
||||
{
|
||||
event->SetInt( "userid", player->GetUserID() );
|
||||
event->SetFloat( "x", GetAbsOrigin().x );
|
||||
event->SetFloat( "y", GetAbsOrigin().y );
|
||||
event->SetFloat( "z", GetAbsOrigin().z );
|
||||
gameeventmanager->FireEvent( event );
|
||||
}
|
||||
}
|
||||
|
||||
UTIL_Remove( this );
|
||||
}
|
||||
|
||||
//TODO: Let physics handle the sound!
|
||||
void CFlashbangProjectile::BounceSound( void )
|
||||
{
|
||||
EmitSound( "Flashbang.Bounce" );
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef HEGRENADE_PROJECTILE_H
|
||||
#define HEGRENADE_PROJECTILE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "basecsgrenade_projectile.h"
|
||||
|
||||
|
||||
class CFlashbangProjectile : public CBaseCSGrenadeProjectile
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CFlashbangProjectile, CBaseCSGrenadeProjectile );
|
||||
|
||||
// Overrides.
|
||||
public:
|
||||
virtual void Spawn();
|
||||
virtual void Precache();
|
||||
virtual void BounceSound( void );
|
||||
virtual void Detonate();
|
||||
|
||||
// Grenade stuff.
|
||||
static CFlashbangProjectile* Create(
|
||||
const Vector &position,
|
||||
const QAngle &angles,
|
||||
const Vector &velocity,
|
||||
const AngularImpulse &angVelocity,
|
||||
CBaseCombatCharacter *pOwner );
|
||||
};
|
||||
|
||||
|
||||
#endif // HEGRENADE_PROJECTILE_H
|
||||
@@ -0,0 +1,345 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "fx_cs_shared.h"
|
||||
#include "weapon_csbase.h"
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
#include "ilagcompensationmanager.h"
|
||||
#endif
|
||||
|
||||
ConVar weapon_accuracy_logging( "weapon_accuracy_logging", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY | FCVAR_ARCHIVE );
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#include "fx_impact.h"
|
||||
|
||||
// this is a cheap ripoff from CBaseCombatWeapon::WeaponSound():
|
||||
void FX_WeaponSound(
|
||||
int iPlayerIndex,
|
||||
WeaponSound_t sound_type,
|
||||
const Vector &vOrigin,
|
||||
CCSWeaponInfo *pWeaponInfo, float flSoundTime )
|
||||
{
|
||||
|
||||
// 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, flSoundTime );
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
int i;
|
||||
// Don't play the sound if it's too close to another impact sound.
|
||||
for ( 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 );
|
||||
|
||||
i = g_GroupedSounds.AddToTail();
|
||||
g_GroupedSounds[i].m_SoundName = pSoundName;
|
||||
g_GroupedSounds[i].m_vPos = vEndPos;
|
||||
}
|
||||
|
||||
|
||||
void StartGroupingSounds()
|
||||
{
|
||||
Assert( g_GroupedSounds.Count() == 0 );
|
||||
SetImpactSoundRoute( ShotgunImpactSoundGroup );
|
||||
}
|
||||
|
||||
|
||||
void EndGroupingSounds()
|
||||
{
|
||||
g_GroupedSounds.Purge();
|
||||
SetImpactSoundRoute( NULL );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "te_shotgun_shot.h"
|
||||
|
||||
// Server doesn't play sounds anyway.
|
||||
void StartGroupingSounds() {}
|
||||
void EndGroupingSounds() {}
|
||||
void FX_WeaponSound ( int iPlayerIndex,
|
||||
WeaponSound_t sound_type,
|
||||
const Vector &vOrigin,
|
||||
CCSWeaponInfo *pWeaponInfo, float flSoundTime ) {};
|
||||
|
||||
#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 fInaccuracy,
|
||||
float fSpread,
|
||||
float flSoundTime
|
||||
)
|
||||
{
|
||||
bool bDoEffects = true;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
C_CSPlayer *pPlayer = ToCSPlayer( ClientEntityList().GetBaseEntity( iPlayerIndex ) );
|
||||
#else
|
||||
CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( iPlayerIndex) );
|
||||
#endif
|
||||
|
||||
const char * weaponAlias = WeaponIDToAlias( iWeaponID );
|
||||
|
||||
if ( !weaponAlias )
|
||||
{
|
||||
DevMsg("FX_FireBullets: weapon alias for ID %i not found\n", iWeaponID );
|
||||
return;
|
||||
}
|
||||
|
||||
#if !defined(CLIENT_DLL)
|
||||
if ( weapon_accuracy_logging.GetBool() )
|
||||
{
|
||||
char szFlags[256];
|
||||
|
||||
V_strcpy(szFlags, " ");
|
||||
|
||||
// #if defined(CLIENT_DLL)
|
||||
// V_strcat(szFlags, "CLIENT ", sizeof(szFlags));
|
||||
// #else
|
||||
// V_strcat(szFlags, "SERVER ", sizeof(szFlags));
|
||||
// #endif
|
||||
//
|
||||
if ( pPlayer->GetMoveType() == MOVETYPE_LADDER )
|
||||
V_strcat(szFlags, "LADDER ", sizeof(szFlags));
|
||||
|
||||
if ( FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
V_strcat(szFlags, "GROUND ", sizeof(szFlags));
|
||||
|
||||
if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING) )
|
||||
V_strcat(szFlags, "DUCKING ", sizeof(szFlags));
|
||||
|
||||
float fVelocity = pPlayer->GetAbsVelocity().Length2D();
|
||||
|
||||
Msg("FireBullets @ %10f [ %s ]: inaccuracy=%f spread=%f max dispersion=%f mode=%2i vel=%10f seed=%3i %s\n",
|
||||
gpGlobals->curtime, weaponAlias, fInaccuracy, fSpread, fInaccuracy + fSpread, iMode, fVelocity, iSeed, szFlags);
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
CCSWeaponInfo *pWeaponInfo = static_cast< CCSWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
|
||||
|
||||
// Do the firing animation event.
|
||||
if ( pPlayer && !pPlayer->IsDormant() )
|
||||
{
|
||||
if ( iMode == Primary_Mode )
|
||||
pPlayer->GetPlayerAnimState()->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_PRIMARY );
|
||||
else
|
||||
pPlayer->GetPlayerAnimState()->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_SECONDARY );
|
||||
}
|
||||
|
||||
#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,
|
||||
fInaccuracy,
|
||||
fSpread
|
||||
);
|
||||
|
||||
|
||||
// Let the player remember the usercmd he fired a weapon on. Assists in making decisions about lag compensation.
|
||||
pPlayer->NoteWeaponFired();
|
||||
|
||||
bDoEffects = false; // no effects on server
|
||||
#endif
|
||||
|
||||
iSeed++;
|
||||
|
||||
int iDamage = pWeaponInfo->m_iDamage;
|
||||
float flRange = pWeaponInfo->m_flRange;
|
||||
int iPenetration = pWeaponInfo->m_iPenetration;
|
||||
float flRangeModifier = pWeaponInfo->m_flRangeModifier;
|
||||
int iAmmoType = pWeaponInfo->iAmmoType;
|
||||
|
||||
WeaponSound_t sound_type = SINGLE;
|
||||
|
||||
// CS HACK, tweak some weapon values based on primary/secondary mode
|
||||
|
||||
if ( iWeaponID == WEAPON_GLOCK )
|
||||
{
|
||||
if ( iMode == Secondary_Mode )
|
||||
{
|
||||
iDamage = 18; // reduced power for burst shots
|
||||
flRangeModifier = 0.9f;
|
||||
}
|
||||
}
|
||||
else if ( iWeaponID == WEAPON_M4A1 )
|
||||
{
|
||||
if ( iMode == Secondary_Mode )
|
||||
{
|
||||
flRangeModifier = 0.95f; // slower bullets in silenced mode
|
||||
sound_type = SPECIAL1;
|
||||
}
|
||||
}
|
||||
else if ( iWeaponID == WEAPON_USP )
|
||||
{
|
||||
if ( iMode == Secondary_Mode )
|
||||
{
|
||||
iDamage = 30; // reduced damage in silenced mode
|
||||
sound_type = SPECIAL1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( bDoEffects)
|
||||
{
|
||||
FX_WeaponSound( iPlayerIndex, sound_type, vOrigin, pWeaponInfo, flSoundTime );
|
||||
}
|
||||
|
||||
|
||||
// Fire bullets, calculate impacts & effects
|
||||
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
StartGroupingSounds();
|
||||
|
||||
#ifdef GAME_DLL
|
||||
pPlayer->StartNewBulletGroup();
|
||||
#endif
|
||||
|
||||
#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 ); // init random system with this seed
|
||||
|
||||
// Get accuracy displacement
|
||||
float fTheta0 = RandomFloat(0.0f, 2.0f * M_PI);
|
||||
float fRadius0 = RandomFloat(0.0f, fInaccuracy);
|
||||
float x0 = fRadius0 * cosf(fTheta0);
|
||||
float y0 = fRadius0 * sinf(fTheta0);
|
||||
|
||||
const int kMaxBullets = 16;
|
||||
float x1[kMaxBullets], y1[kMaxBullets];
|
||||
Assert(pWeaponInfo->m_iBullets <= kMaxBullets);
|
||||
|
||||
// the RNG can be desynchronized by FireBullet(), so pre-generate all spread offsets
|
||||
for ( int iBullet=0; iBullet < pWeaponInfo->m_iBullets; iBullet++ )
|
||||
{
|
||||
float fTheta1 = RandomFloat(0.0f, 2.0f * M_PI);
|
||||
float fRadius1 = RandomFloat(0.0f, fSpread);
|
||||
x1[iBullet] = fRadius1 * cosf(fTheta1);
|
||||
y1[iBullet] = fRadius1 * sinf(fTheta1);
|
||||
}
|
||||
|
||||
for ( int iBullet=0; iBullet < pWeaponInfo->m_iBullets; iBullet++ )
|
||||
{
|
||||
pPlayer->FireBullet(
|
||||
vOrigin,
|
||||
vAngles,
|
||||
flRange,
|
||||
iPenetration,
|
||||
iAmmoType,
|
||||
iDamage,
|
||||
flRangeModifier,
|
||||
pPlayer,
|
||||
bDoEffects,
|
||||
x0 + x1[iBullet], y0 + y1[iBullet] );
|
||||
}
|
||||
|
||||
#if !defined (CLIENT_DLL)
|
||||
lagcompensation->FinishLagCompensation( pPlayer );
|
||||
#endif
|
||||
|
||||
EndGroupingSounds();
|
||||
}
|
||||
|
||||
// This runs on both the client and the server.
|
||||
// On the server, it dispatches a TE_PlantBomb to visible clients.
|
||||
// On the client, it plays the planting animation.
|
||||
void FX_PlantBomb( int iPlayerIndex, const Vector &vOrigin, PlantBombOption_t option )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
C_CSPlayer *pPlayer = ToCSPlayer( ClientEntityList().GetBaseEntity( iPlayerIndex ) );
|
||||
#else
|
||||
CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( iPlayerIndex) );
|
||||
#endif
|
||||
|
||||
// Do the firing animation event.
|
||||
if ( pPlayer && !pPlayer->IsDormant() )
|
||||
{
|
||||
switch ( option )
|
||||
{
|
||||
case PLANTBOMB_PLANT:
|
||||
{
|
||||
pPlayer->GetPlayerAnimState()->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_PRIMARY );
|
||||
}
|
||||
break;
|
||||
|
||||
case PLANTBOMB_ABORT:
|
||||
{
|
||||
pPlayer->GetPlayerAnimState()->DoAnimationEvent( PLAYERANIMEVENT_CLEAR_FIRING );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#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_PlantBomb( iPlayerIndex, vOrigin, option );
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef FX_CS_SHARED_H
|
||||
#define FX_CS_SHARED_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_cs_player.h"
|
||||
#else
|
||||
#include "cs_player.h"
|
||||
#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 iPlayer,
|
||||
const Vector &vOrigin,
|
||||
const QAngle &vAngles,
|
||||
int iWeaponID,
|
||||
int iMode,
|
||||
int iSeed,
|
||||
float fInaccuracy,
|
||||
float fSpread,
|
||||
float flSoundTime = 0.0f
|
||||
);
|
||||
|
||||
// This runs on both the client and the server.
|
||||
// On the server, it dispatches a TE_PlantBomb to visible clients.
|
||||
// On the client, it plays the planting animation.
|
||||
enum PlantBombOption_t
|
||||
{
|
||||
PLANTBOMB_PLANT, // play the planting animation
|
||||
PLANTBOMB_ABORT, // abort the planting animation
|
||||
// NOTE: If you add additional items to this enum then m_option in CTEPlantBomb will need to have its SendPropInt setting changed to have more than one bit.
|
||||
};
|
||||
void FX_PlantBomb( int iPlayer, const Vector &vOrigin, PlantBombOption_t option );
|
||||
|
||||
#endif // FX_CS_SHARED_H
|
||||
@@ -0,0 +1,94 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "hegrenade_projectile.h"
|
||||
#include "soundent.h"
|
||||
#include "cs_player.h"
|
||||
#include "KeyValues.h"
|
||||
#include "weapon_csbase.h"
|
||||
|
||||
#define GRENADE_MODEL "models/Weapons/w_eq_fraggrenade_thrown.mdl"
|
||||
|
||||
|
||||
LINK_ENTITY_TO_CLASS( hegrenade_projectile, CHEGrenadeProjectile );
|
||||
PRECACHE_WEAPON_REGISTER( hegrenade_projectile );
|
||||
|
||||
CHEGrenadeProjectile* CHEGrenadeProjectile::Create(
|
||||
const Vector &position,
|
||||
const QAngle &angles,
|
||||
const Vector &velocity,
|
||||
const AngularImpulse &angVelocity,
|
||||
CBaseCombatCharacter *pOwner,
|
||||
float timer )
|
||||
{
|
||||
CHEGrenadeProjectile *pGrenade = (CHEGrenadeProjectile*)CBaseEntity::Create( "hegrenade_projectile", position, angles, pOwner );
|
||||
|
||||
// Set the timer for 1 second less than requested. We're going to issue a SOUND_DANGER
|
||||
// one second before detonation.
|
||||
|
||||
pGrenade->SetDetonateTimerLength( 1.5 );
|
||||
pGrenade->SetAbsVelocity( velocity );
|
||||
pGrenade->SetupInitialTransmittedGrenadeVelocity( velocity );
|
||||
pGrenade->SetThrower( pOwner );
|
||||
|
||||
pGrenade->SetGravity( BaseClass::GetGrenadeGravity() );
|
||||
pGrenade->SetFriction( BaseClass::GetGrenadeFriction() );
|
||||
pGrenade->SetElasticity( BaseClass::GetGrenadeElasticity() );
|
||||
|
||||
pGrenade->m_flDamage = 100;
|
||||
pGrenade->m_DmgRadius = pGrenade->m_flDamage * 3.5f;
|
||||
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
|
||||
pGrenade->ApplyLocalAngularVelocityImpulse( angVelocity );
|
||||
|
||||
// make NPCs afaid of it while in the air
|
||||
pGrenade->SetThink( &CHEGrenadeProjectile::DangerSoundThink );
|
||||
pGrenade->SetNextThink( gpGlobals->curtime );
|
||||
|
||||
pGrenade->m_pWeaponInfo = GetWeaponInfo( WEAPON_HEGRENADE );
|
||||
|
||||
return pGrenade;
|
||||
}
|
||||
|
||||
void CHEGrenadeProjectile::Spawn()
|
||||
{
|
||||
SetModel( GRENADE_MODEL );
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
void CHEGrenadeProjectile::Precache()
|
||||
{
|
||||
PrecacheModel( GRENADE_MODEL );
|
||||
|
||||
PrecacheScriptSound( "HEGrenade.Bounce" );
|
||||
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
void CHEGrenadeProjectile::BounceSound( void )
|
||||
{
|
||||
EmitSound( "HEGrenade.Bounce" );
|
||||
}
|
||||
|
||||
void CHEGrenadeProjectile::Detonate()
|
||||
{
|
||||
BaseClass::Detonate();
|
||||
|
||||
// tell the bots an HE grenade has exploded
|
||||
CCSPlayer *player = ToCSPlayer(GetThrower());
|
||||
if ( player )
|
||||
{
|
||||
IGameEvent * event = gameeventmanager->CreateEvent( "hegrenade_detonate" );
|
||||
if ( event )
|
||||
{
|
||||
event->SetInt( "userid", player->GetUserID() );
|
||||
event->SetFloat( "x", GetAbsOrigin().x );
|
||||
event->SetFloat( "y", GetAbsOrigin().y );
|
||||
event->SetFloat( "z", GetAbsOrigin().z );
|
||||
gameeventmanager->FireEvent( event );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef HEGRENADE_PROJECTILE_H
|
||||
#define HEGRENADE_PROJECTILE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "basecsgrenade_projectile.h"
|
||||
|
||||
class CHEGrenadeProjectile : public CBaseCSGrenadeProjectile
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CHEGrenadeProjectile, CBaseCSGrenadeProjectile );
|
||||
|
||||
|
||||
// Overrides.
|
||||
public:
|
||||
virtual void Spawn();
|
||||
virtual void Precache();
|
||||
virtual void BounceSound( void );
|
||||
virtual void Detonate();
|
||||
|
||||
// Grenade stuff.
|
||||
public:
|
||||
|
||||
static CHEGrenadeProjectile* Create(
|
||||
const Vector &position,
|
||||
const QAngle &angles,
|
||||
const Vector &velocity,
|
||||
const AngularImpulse &angVelocity,
|
||||
CBaseCombatCharacter *pOwner,
|
||||
float timer );
|
||||
|
||||
void SetTimer( float timer );
|
||||
|
||||
private:
|
||||
float m_flDetonateTime;
|
||||
};
|
||||
|
||||
|
||||
#endif // HEGRENADE_PROJECTILE_H
|
||||
@@ -0,0 +1,103 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CAK47 C_AK47
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CAK47 : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CAK47, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CAK47();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_AK47; }
|
||||
|
||||
private:
|
||||
CAK47( const CAK47 & );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( AK47, DT_WeaponAK47 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CAK47, DT_WeaponAK47 )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CAK47 )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_ak47, CAK47 );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_ak47 );
|
||||
|
||||
// ---------------------------------------------------------------------------- //
|
||||
// CAK47 implementation.
|
||||
// ---------------------------------------------------------------------------- //
|
||||
|
||||
CAK47::CAK47()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
float CAK47::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 0.04f + 0.4f * m_flAccuracy;
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 140)
|
||||
return 0.04f + 0.07f * m_flAccuracy;
|
||||
else
|
||||
return 0.0275f * m_flAccuracy;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
|
||||
void CAK47::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( !CSBaseGunFire( GetCSWpnData().m_flCycleTime, Primary_Mode ) )
|
||||
return;
|
||||
|
||||
// CSBaseGunFire can kill us, forcing us to drop our weapon, if we shoot something that explodes
|
||||
pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if (pPlayer->GetAbsVelocity().Length2D() > 5 )
|
||||
pPlayer->KickBack ( 1.5, 0.45, 0.225, 0.05, 6.5, 2.5, 7 );
|
||||
else if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
pPlayer->KickBack ( 2, 1.0, 0.5, 0.35, 9, 6, 5 );
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
pPlayer->KickBack ( 0.9, 0.35, 0.15, 0.025, 5.5, 1.5, 9 );
|
||||
else
|
||||
pPlayer->KickBack ( 1, 0.375, 0.175, 0.0375, 5.75, 1.75, 8 );
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponAug C_WeaponAug
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponAug : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponAug, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponAug();
|
||||
|
||||
virtual void SecondaryAttack();
|
||||
virtual void PrimaryAttack();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
virtual bool Reload();
|
||||
virtual bool Deploy();
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_AUG; }
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
virtual bool HideViewModelWhenZoomed( void ) { return false; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
void AUGFire( float flSpread, bool bZoomed );
|
||||
|
||||
CWeaponAug( const CWeaponAug & );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponAug, DT_WeaponAug )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponAug, DT_WeaponAug )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponAug )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_aug, CWeaponAug );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_aug );
|
||||
|
||||
|
||||
|
||||
CWeaponAug::CWeaponAug()
|
||||
{
|
||||
}
|
||||
|
||||
void CWeaponAug::SecondaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( pPlayer->GetFOV() == pPlayer->GetDefaultFOV() )
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, 55, 0.2f );
|
||||
m_weaponMode = Secondary_Mode;
|
||||
}
|
||||
else if ( pPlayer->GetFOV() == 55 )
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV(), 0.15f );
|
||||
m_weaponMode = Primary_Mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV() );
|
||||
m_weaponMode = Primary_Mode;
|
||||
}
|
||||
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 0.3;
|
||||
}
|
||||
|
||||
|
||||
float CWeaponAug::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 0.035f + 0.4f * m_flAccuracy;
|
||||
|
||||
else if ( pPlayer->GetAbsVelocity().Length2D() > 140 )
|
||||
return 0.035f + 0.07f * m_flAccuracy;
|
||||
else
|
||||
return 0.02f * m_flAccuracy;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CWeaponAug::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
bool bZoomed = pPlayer->GetFOV() < pPlayer->GetDefaultFOV();
|
||||
|
||||
float flCycleTime = GetCSWpnData().m_flCycleTime;
|
||||
|
||||
if ( bZoomed )
|
||||
flCycleTime = 0.135f;
|
||||
|
||||
if ( !CSBaseGunFire( flCycleTime, m_weaponMode ) )
|
||||
return;
|
||||
|
||||
// CSBaseGunFire can kill us, forcing us to drop our weapon, if we shoot something that explodes
|
||||
pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( pPlayer->GetAbsVelocity().Length2D() > 5 )
|
||||
pPlayer->KickBack ( 1, 0.45, 0.275, 0.05, 4, 2.5, 7 );
|
||||
|
||||
else if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
pPlayer->KickBack ( 1.25, 0.45, 0.22, 0.18, 5.5, 4, 5 );
|
||||
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
pPlayer->KickBack ( 0.575, 0.325, 0.2, 0.011, 3.25, 2, 8 );
|
||||
|
||||
else
|
||||
pPlayer->KickBack ( 0.625, 0.375, 0.25, 0.0125, 3.5, 2.25, 8 );
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponAug::Reload()
|
||||
{
|
||||
m_weaponMode = Primary_Mode;
|
||||
return BaseClass::Reload();
|
||||
}
|
||||
|
||||
bool CWeaponAug::Deploy()
|
||||
{
|
||||
m_weaponMode = Primary_Mode;
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponAWP C_WeaponAWP
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
#include "KeyValues.h"
|
||||
|
||||
#endif
|
||||
|
||||
#define SNIPER_ZOOM_CONTEXT "SniperRifleThink"
|
||||
|
||||
const int cAWPMidZoomFOV = 40;
|
||||
const int cAWPMaxZoomFOV = 10;
|
||||
|
||||
#ifdef AWP_UNZOOM
|
||||
ConVar sv_awpunzoomdelay(
|
||||
"sv_awpunzoomdelay",
|
||||
"1.0",
|
||||
0,
|
||||
"how many seconds to zoom the zoom up after firing",
|
||||
true, 0, // min value
|
||||
false, 0 // max value
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponAWP : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponAWP, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_DATADESC();
|
||||
#endif
|
||||
|
||||
CWeaponAWP();
|
||||
|
||||
virtual void Spawn();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
virtual void SecondaryAttack();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
virtual float GetMaxSpeed() const;
|
||||
virtual bool IsAwp() const;
|
||||
virtual bool Reload();
|
||||
virtual bool Deploy();
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_AWP; }
|
||||
|
||||
private:
|
||||
|
||||
#ifdef AWP_UNZOOM
|
||||
void UnzoomThink( void );
|
||||
#endif
|
||||
|
||||
CWeaponAWP( const CWeaponAWP & );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponAWP, DT_WeaponAWP )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponAWP, DT_WeaponAWP )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponAWP )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_awp, CWeaponAWP );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_awp );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
BEGIN_DATADESC( CWeaponAWP )
|
||||
#ifdef AWP_UNZOOM
|
||||
DEFINE_THINKFUNC( UnzoomThink ),
|
||||
#endif
|
||||
END_DATADESC()
|
||||
|
||||
#endif
|
||||
|
||||
CWeaponAWP::CWeaponAWP()
|
||||
{
|
||||
}
|
||||
|
||||
void CWeaponAWP::Spawn()
|
||||
{
|
||||
Precache();
|
||||
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
|
||||
void CWeaponAWP::SecondaryAttack()
|
||||
{
|
||||
const float kZoomTime = 0.10f;
|
||||
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
|
||||
if ( pPlayer == NULL )
|
||||
{
|
||||
Assert( pPlayer != NULL );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( pPlayer->GetFOV() == pPlayer->GetDefaultFOV() )
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, cAWPMidZoomFOV, kZoomTime );
|
||||
m_weaponMode = Secondary_Mode;
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyAltSwitch;
|
||||
}
|
||||
else if ( pPlayer->GetFOV() == cAWPMidZoomFOV )
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, cAWPMaxZoomFOV, kZoomTime );
|
||||
m_weaponMode = Secondary_Mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV(), kZoomTime );
|
||||
m_weaponMode = Primary_Mode;
|
||||
}
|
||||
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// If this isn't guarded, the sound will be emitted twice, once by the server and once by the client.
|
||||
// Let the server play it since if only the client plays it, it's liable to get played twice cause of
|
||||
// a prediction error. joy.
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [tj] Playing this from the player so that we don't try to play the sound outside the level.
|
||||
//=============================================================================
|
||||
if ( GetPlayerOwner() )
|
||||
{
|
||||
GetPlayerOwner()->EmitSound( "Default.Zoom" );
|
||||
}
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
// let the bots hear the rifle zoom
|
||||
IGameEvent * event = gameeventmanager->CreateEvent( "weapon_zoom" );
|
||||
if ( event )
|
||||
{
|
||||
event->SetInt( "userid", pPlayer->GetUserID() );
|
||||
gameeventmanager->FireEvent( event );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 0.3f;
|
||||
m_zoomFullyActiveTime = gpGlobals->curtime + 0.15; // The worst zoom time from above.
|
||||
|
||||
}
|
||||
|
||||
float CWeaponAWP::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
float fSpread = 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
fSpread = 0.85f;
|
||||
|
||||
else if ( pPlayer->GetAbsVelocity().Length2D() > 140 )
|
||||
fSpread = 0.25f;
|
||||
|
||||
else if ( pPlayer->GetAbsVelocity().Length2D() > 10 )
|
||||
fSpread = 0.10f;
|
||||
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
fSpread = 0.0f;
|
||||
|
||||
else
|
||||
fSpread = 0.001f;
|
||||
|
||||
// If we are not zoomed in, or we have very recently zoomed and are still transitioning, the bullet diverts more.
|
||||
if (pPlayer->GetFOV() == pPlayer->GetDefaultFOV() || (gpGlobals->curtime < m_zoomFullyActiveTime))
|
||||
{
|
||||
fSpread += 0.08f;
|
||||
}
|
||||
|
||||
return fSpread;
|
||||
}
|
||||
else
|
||||
{
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
}
|
||||
|
||||
void CWeaponAWP::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( !CSBaseGunFire( GetCSWpnData().m_flCycleTime, m_weaponMode ) )
|
||||
return;
|
||||
|
||||
if ( m_weaponMode == Secondary_Mode )
|
||||
{
|
||||
float midFOVdistance = fabs( pPlayer->GetFOV() - (float)cAWPMidZoomFOV );
|
||||
float farFOVdistance = fabs( pPlayer->GetFOV() - (float)cAWPMaxZoomFOV );
|
||||
if ( midFOVdistance < farFOVdistance )
|
||||
{
|
||||
pPlayer->m_iLastZoom = cAWPMidZoomFOV;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPlayer->m_iLastZoom = cAWPMaxZoomFOV;
|
||||
}
|
||||
|
||||
#ifdef AWP_UNZOOM
|
||||
SetContextThink( &CWeaponAWP::UnzoomThink, gpGlobals->curtime + sv_awpunzoomdelay.GetFloat(), SNIPER_ZOOM_CONTEXT );
|
||||
#else
|
||||
pPlayer->m_bResumeZoom = true;
|
||||
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV(), 0.1f );
|
||||
m_weaponMode = Primary_Mode;
|
||||
#endif
|
||||
}
|
||||
|
||||
QAngle angle = pPlayer->GetPunchAngle();
|
||||
angle.x -= 2;
|
||||
pPlayer->SetPunchAngle( angle );
|
||||
}
|
||||
|
||||
#ifdef AWP_UNZOOM
|
||||
void CWeaponAWP::UnzoomThink( void )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
|
||||
if (pPlayer == NULL)
|
||||
{
|
||||
Assert(pPlayer != NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV(), 0.1f );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
float CWeaponAWP::GetMaxSpeed() const
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
|
||||
if (pPlayer == NULL)
|
||||
{
|
||||
Assert(pPlayer != NULL);
|
||||
return BaseClass::GetMaxSpeed();
|
||||
}
|
||||
|
||||
if ( pPlayer->GetFOV() == pPlayer->GetDefaultFOV() )
|
||||
{
|
||||
return BaseClass::GetMaxSpeed();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Slower speed when zoomed in.
|
||||
return 150;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponAWP::IsAwp() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponAWP::Reload()
|
||||
{
|
||||
m_weaponMode = Primary_Mode;
|
||||
return BaseClass::Reload();
|
||||
}
|
||||
|
||||
bool CWeaponAWP::Deploy()
|
||||
{
|
||||
// don't allow weapon switching to shortcut cycle time (quickswitch exploit)
|
||||
float fOldNextPrimaryAttack = m_flNextPrimaryAttack;
|
||||
float fOldNextSecondaryAttack = m_flNextSecondaryAttack;
|
||||
|
||||
if ( !BaseClass::Deploy() )
|
||||
return false;
|
||||
|
||||
m_weaponMode = Primary_Mode;
|
||||
m_flNextPrimaryAttack = MAX( m_flNextPrimaryAttack, fOldNextPrimaryAttack );
|
||||
m_flNextSecondaryAttack = MAX( m_flNextSecondaryAttack, fOldNextSecondaryAttack );
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "gamerules.h"
|
||||
#include "npcevent.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "weapon_basecsgrenade.h"
|
||||
#include "in_buttons.h"
|
||||
#include "datacache/imdlcache.h"
|
||||
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
#include "items.h"
|
||||
#include "../../server/cstrike/cs_gamestats.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define GRENADE_TIMER 1.5f //Seconds
|
||||
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( BaseCSGrenade, DT_BaseCSGrenade )
|
||||
|
||||
BEGIN_NETWORK_TABLE(CBaseCSGrenade, DT_BaseCSGrenade)
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
SendPropBool( SENDINFO(m_bRedraw) ),
|
||||
SendPropBool( SENDINFO(m_bPinPulled) ),
|
||||
SendPropFloat( SENDINFO(m_fThrowTime), 0, SPROP_NOSCALE ),
|
||||
#else
|
||||
RecvPropBool( RECVINFO(m_bRedraw) ),
|
||||
RecvPropBool( RECVINFO(m_bPinPulled) ),
|
||||
RecvPropFloat( RECVINFO(m_fThrowTime) ),
|
||||
#endif
|
||||
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#if defined CLIENT_DLL
|
||||
BEGIN_PREDICTION_DATA( CBaseCSGrenade )
|
||||
DEFINE_PRED_FIELD( m_bRedraw, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_bRedraw, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_basecsgrenade, CBaseCSGrenade );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
ConVar sv_ignoregrenaderadio( "sv_ignoregrenaderadio", "0", 0, "Turn off Fire in the hole messages" );
|
||||
#endif
|
||||
|
||||
CBaseCSGrenade::CBaseCSGrenade()
|
||||
{
|
||||
m_bRedraw = false;
|
||||
m_bPinPulled = false;
|
||||
m_fThrowTime = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseCSGrenade::Precache()
|
||||
{
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseCSGrenade::Deploy()
|
||||
{
|
||||
m_bRedraw = false;
|
||||
m_bPinPulled = false;
|
||||
m_fThrowTime = 0;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// if we're officially out of grenades, ditch this weapon
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return false;
|
||||
|
||||
if( pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
|
||||
{
|
||||
pPlayer->Weapon_Drop( this, NULL, NULL );
|
||||
UTIL_Remove(this);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseCSGrenade::Holster( CBaseCombatWeapon *pSwitchingTo )
|
||||
{
|
||||
m_bRedraw = false;
|
||||
m_bPinPulled = false; // when this is holstered make sure the pin isn’t pulled.
|
||||
m_fThrowTime = 0;
|
||||
|
||||
#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.
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return false;
|
||||
|
||||
if( pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
|
||||
{
|
||||
CBaseCombatCharacter *pOwner = (CBaseCombatCharacter *)pPlayer;
|
||||
pOwner->Weapon_Drop( this );
|
||||
UTIL_Remove(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
return BaseClass::Holster( pSwitchingTo );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseCSGrenade::PrimaryAttack()
|
||||
{
|
||||
if ( m_bRedraw || m_bPinPulled || m_fThrowTime > 0.0f )
|
||||
return;
|
||||
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer || pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
|
||||
return;
|
||||
|
||||
// The pull pin animation has to finish, then we wait until they aren't holding the primary
|
||||
// attack button, then throw the grenade.
|
||||
SendWeaponAnim( ACT_VM_PULLPIN );
|
||||
m_bPinPulled = true;
|
||||
|
||||
// Don't let weapon idle interfere in the middle of a throw!
|
||||
MDLCACHE_CRITICAL_SECTION();
|
||||
SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
|
||||
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseCSGrenade::SecondaryAttack()
|
||||
{
|
||||
if ( m_bRedraw )
|
||||
return;
|
||||
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
|
||||
if ( pPlayer == NULL )
|
||||
return;
|
||||
|
||||
//See if we're ducking
|
||||
if ( pPlayer->GetFlags() & FL_DUCKING )
|
||||
{
|
||||
//Send the weapon animation
|
||||
SendWeaponAnim( ACT_VM_SECONDARYATTACK );
|
||||
}
|
||||
else
|
||||
{
|
||||
//Send the weapon animation
|
||||
SendWeaponAnim( ACT_VM_HAULBACK );
|
||||
}
|
||||
|
||||
// Don't let weapon idle interfere in the middle of a throw!
|
||||
SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
|
||||
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseCSGrenade::Reload()
|
||||
{
|
||||
if ( ( m_bRedraw ) && ( m_flNextPrimaryAttack <= gpGlobals->curtime ) && ( m_flNextSecondaryAttack <= gpGlobals->curtime ) )
|
||||
{
|
||||
//Redraw the weapon
|
||||
SendWeaponAnim( ACT_VM_DRAW );
|
||||
|
||||
//Update our times
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
|
||||
SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
|
||||
|
||||
//Mark this as done
|
||||
// m_bRedraw = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseCSGrenade::ItemPostFrame()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
CBaseViewModel *vm = pPlayer->GetViewModel( m_nViewModelIndex );
|
||||
if ( !vm )
|
||||
return;
|
||||
|
||||
// If they let go of the fire button, they want to throw the grenade.
|
||||
if ( m_bPinPulled && !(pPlayer->m_nButtons & IN_ATTACK) )
|
||||
{
|
||||
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_THROW_GRENADE );
|
||||
|
||||
StartGrenadeThrow();
|
||||
|
||||
MDLCACHE_CRITICAL_SECTION();
|
||||
m_bPinPulled = false;
|
||||
SendWeaponAnim( ACT_VM_THROW );
|
||||
SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
|
||||
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); // we're still throwing, so reset our next primary attack
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
IGameEvent * event = gameeventmanager->CreateEvent( "weapon_fire" );
|
||||
if( event )
|
||||
{
|
||||
const char *weaponName = STRING( m_iClassname );
|
||||
if ( strncmp( weaponName, "weapon_", 7 ) == 0 )
|
||||
{
|
||||
weaponName += 7;
|
||||
}
|
||||
|
||||
event->SetInt( "userid", pPlayer->GetUserID() );
|
||||
event->SetString( "weapon", weaponName );
|
||||
gameeventmanager->FireEvent( event );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if ((m_fThrowTime > 0) && (m_fThrowTime < gpGlobals->curtime))
|
||||
{
|
||||
// only decrement our ammo when we actually create the projectile
|
||||
DecrementAmmo( pPlayer );
|
||||
|
||||
ThrowGrenade();
|
||||
}
|
||||
else if( m_bRedraw )
|
||||
{
|
||||
// Has the throw animation finished playing
|
||||
if( m_flTimeWeaponIdle < gpGlobals->curtime )
|
||||
{
|
||||
#ifdef GAME_DLL
|
||||
// if we're officially out of grenades, ditch this weapon
|
||||
if( pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
|
||||
{
|
||||
pPlayer->Weapon_Drop( this, NULL, NULL );
|
||||
UTIL_Remove(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
pPlayer->SwitchToNextBestWeapon( this );
|
||||
}
|
||||
#endif
|
||||
return; //don't animate this grenade any more!
|
||||
}
|
||||
}
|
||||
else if( !m_bRedraw )
|
||||
{
|
||||
BaseClass::ItemPostFrame();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
void CBaseCSGrenade::DecrementAmmo( CBaseCombatCharacter *pOwner )
|
||||
{
|
||||
}
|
||||
|
||||
void CBaseCSGrenade::DropGrenade()
|
||||
{
|
||||
m_bRedraw = true;
|
||||
m_fThrowTime = 0.0f;
|
||||
}
|
||||
|
||||
void CBaseCSGrenade::ThrowGrenade()
|
||||
{
|
||||
m_bRedraw = true;
|
||||
m_fThrowTime = 0.0f;
|
||||
}
|
||||
|
||||
void CBaseCSGrenade::StartGrenadeThrow()
|
||||
{
|
||||
m_fThrowTime = gpGlobals->curtime + 0.1f;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
BEGIN_DATADESC( CBaseCSGrenade )
|
||||
DEFINE_FIELD( m_bRedraw, FIELD_BOOLEAN ),
|
||||
END_DATADESC()
|
||||
|
||||
int CBaseCSGrenade::CapabilitiesGet()
|
||||
{
|
||||
return bits_CAP_WEAPON_RANGE_ATTACK1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pOwner -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseCSGrenade::DecrementAmmo( CBaseCombatCharacter *pOwner )
|
||||
{
|
||||
pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
|
||||
}
|
||||
|
||||
void CBaseCSGrenade::StartGrenadeThrow()
|
||||
{
|
||||
m_fThrowTime = gpGlobals->curtime + 0.1f;
|
||||
}
|
||||
|
||||
void CBaseCSGrenade::ThrowGrenade()
|
||||
{
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
if ( !pPlayer )
|
||||
{
|
||||
Assert( false );
|
||||
return;
|
||||
}
|
||||
|
||||
QAngle angThrow = pPlayer->LocalEyeAngles();
|
||||
|
||||
Vector vForward, vRight, vUp;
|
||||
|
||||
if ( angThrow.x < 0 )
|
||||
{
|
||||
angThrow.x += 360; // make sure we have a positive angle from LocalEyeAngles()
|
||||
}
|
||||
|
||||
if ( angThrow.x < 90 )
|
||||
angThrow.x = -10 + angThrow.x * ((90 + 10) / 90.0);
|
||||
else
|
||||
{
|
||||
angThrow.x = 360.0f - angThrow.x;
|
||||
angThrow.x = -10 + angThrow.x * -((90 - 10) / 90.0);
|
||||
}
|
||||
|
||||
float flVel = (90 - angThrow.x) * 6;
|
||||
|
||||
if (flVel > 750)
|
||||
flVel = 750;
|
||||
|
||||
AngleVectors( angThrow, &vForward, &vRight, &vUp );
|
||||
|
||||
Vector vecSrc = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset();
|
||||
|
||||
// We want to throw the grenade from 16 units out. But that can cause problems if we're facing
|
||||
// a thin wall. Do a hull trace to be safe.
|
||||
trace_t trace;
|
||||
Vector mins( -2, -2, -2 );
|
||||
Vector maxs( 2, 2, 2 );
|
||||
UTIL_TraceHull( vecSrc, vecSrc + vForward * 16, mins, maxs, MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &trace );
|
||||
vecSrc = trace.endpos;
|
||||
|
||||
Vector vecThrow = vForward * flVel + pPlayer->GetAbsVelocity();
|
||||
|
||||
EmitGrenade( vecSrc, vec3_angle, vecThrow, AngularImpulse(600,random->RandomInt(-1200,1200),0), pPlayer );
|
||||
|
||||
m_bRedraw = true;
|
||||
m_fThrowTime = 0.0f;
|
||||
|
||||
CCSPlayer *pCSPlayer = ToCSPlayer( pPlayer );
|
||||
|
||||
if( pCSPlayer )
|
||||
{
|
||||
if ( !sv_ignoregrenaderadio.GetBool() )
|
||||
{
|
||||
pCSPlayer->Radio( "Radio.FireInTheHole", "#Cstrike_TitlesTXT_Fire_in_the_hole" );
|
||||
}
|
||||
CCS_GameStats.IncrementStat(pCSPlayer, CSSTAT_GRENADES_THROWN, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseCSGrenade::DropGrenade()
|
||||
{
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
if ( !pPlayer )
|
||||
{
|
||||
Assert( false );
|
||||
return;
|
||||
}
|
||||
|
||||
Vector vForward;
|
||||
pPlayer->EyeVectors( &vForward );
|
||||
Vector vecSrc = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset() + vForward * 16;
|
||||
|
||||
Vector vecVel = pPlayer->GetAbsVelocity();
|
||||
|
||||
EmitGrenade( vecSrc, vec3_angle, vecVel, AngularImpulse(600,random->RandomInt(-1200,1200),0), pPlayer );
|
||||
|
||||
CCSPlayer *pCSPlayer = ToCSPlayer( pPlayer );
|
||||
|
||||
if( pCSPlayer )
|
||||
{
|
||||
CCS_GameStats.IncrementStat(pCSPlayer, CSSTAT_GRENADES_THROWN, 1);
|
||||
}
|
||||
|
||||
m_bRedraw = true;
|
||||
m_fThrowTime = 0.0f;
|
||||
}
|
||||
|
||||
void CBaseCSGrenade::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer )
|
||||
{
|
||||
Assert( 0 && "CBaseCSGrenade::EmitGrenade should not be called. Make sure to implement this in your subclass!\n" );
|
||||
}
|
||||
|
||||
bool CBaseCSGrenade::AllowsAutoSwitchFrom( void ) const
|
||||
{
|
||||
return !m_bPinPulled;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef WEAPON_BASECSGRENADE_H
|
||||
#define WEAPON_BASECSGRENADE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "weapon_csbase.h"
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#define CBaseCSGrenade C_BaseCSGrenade
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CBaseCSGrenade : public CWeaponCSBase
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CBaseCSGrenade, CWeaponCSBase );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CBaseCSGrenade();
|
||||
|
||||
virtual void Precache();
|
||||
|
||||
bool Deploy();
|
||||
bool Holster( CBaseCombatWeapon *pSwitchingTo );
|
||||
|
||||
void PrimaryAttack();
|
||||
void SecondaryAttack();
|
||||
|
||||
// virtual float GetSpread() const;
|
||||
|
||||
bool Reload();
|
||||
|
||||
virtual void ItemPostFrame();
|
||||
|
||||
void DecrementAmmo( CBaseCombatCharacter *pOwner );
|
||||
virtual void StartGrenadeThrow();
|
||||
virtual void ThrowGrenade();
|
||||
virtual void DropGrenade();
|
||||
|
||||
bool IsPinPulled() const;
|
||||
bool IsBeingThrown() const { return m_fThrowTime > 0; }
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_DATADESC();
|
||||
|
||||
virtual bool AllowsAutoSwitchFrom( void ) const;
|
||||
|
||||
int CapabilitiesGet();
|
||||
|
||||
// Each derived grenade class implements this.
|
||||
virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer );
|
||||
#endif
|
||||
|
||||
protected:
|
||||
CNetworkVar( 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( float, m_fThrowTime ); // the time at which the grenade will be thrown. If this value is 0 then the time hasn't been set yet.
|
||||
|
||||
private:
|
||||
CBaseCSGrenade( const CBaseCSGrenade & ) {}
|
||||
};
|
||||
|
||||
|
||||
inline bool CBaseCSGrenade::IsPinPulled() const
|
||||
{
|
||||
return m_bPinPulled;
|
||||
}
|
||||
|
||||
|
||||
#endif // WEAPON_BASECSGRENADE_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,221 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef WEAPON_C4_H
|
||||
#define WEAPON_C4_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "weapon_csbase.h"
|
||||
#include "utlvector.h"
|
||||
|
||||
#define NUM_BEEPS 7
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CC4 C_C4
|
||||
|
||||
#else
|
||||
|
||||
// ------------------------------------------------------------------------------------------ //
|
||||
// CPlantedC4 class.
|
||||
// ------------------------------------------------------------------------------------------ //
|
||||
|
||||
class CPlantedC4 : public CBaseAnimating
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CPlantedC4, CBaseAnimating );
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CPlantedC4();
|
||||
virtual ~CPlantedC4();
|
||||
|
||||
virtual int UpdateTransmitState();
|
||||
virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways );
|
||||
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo );
|
||||
|
||||
static CPlantedC4* ShootSatchelCharge( CCSPlayer *pevOwner, Vector vecStart, QAngle vecAngles );
|
||||
virtual void Precache();
|
||||
|
||||
// Set these flags so CTs can use the C4 to disarm it.
|
||||
virtual int ObjectCaps() { return BaseClass::ObjectCaps() | (FCAP_CONTINUOUS_USE | FCAP_USE_IN_RADIUS); }
|
||||
|
||||
void SetBombSiteIndex( int iIndex ){ m_iBombSiteIndex = iIndex; }
|
||||
|
||||
inline bool IsBombActive( void ) { return m_bBombTicking; }
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [tj] Accessors related to planting of the bomb
|
||||
//=============================================================================
|
||||
|
||||
CCSPlayer* GetPlanter() { return m_pPlanter; }
|
||||
void SetPlanter(CCSPlayer* player) { m_pPlanter = player; }
|
||||
|
||||
void SetPlantedAfterPickup (bool plantedAfterPickup) { m_bPlantedAfterPickup = plantedAfterPickup; }
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
|
||||
public:
|
||||
|
||||
CNetworkVar( bool, m_bBombTicking );
|
||||
CNetworkVar( float, m_flC4Blow );
|
||||
|
||||
private:
|
||||
|
||||
void Init( CCSPlayer *pevOwner, Vector vecStart, QAngle vecAngles );
|
||||
void C4Think();
|
||||
|
||||
// This becomes the think function when the timer has expired and it is about to explode.
|
||||
void DetonateThink();
|
||||
void Explode( trace_t *pTrace, int bitsDamageType );
|
||||
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
// Replicate timer length to the client for effects
|
||||
CNetworkVar( float, m_flTimerLength );
|
||||
|
||||
// Info for defusing.
|
||||
CHandle<CCSPlayer> m_pBombDefuser;
|
||||
float m_flNextDefuse;
|
||||
bool m_bStartDefuse;
|
||||
int m_iBombSiteIndex;
|
||||
|
||||
CNetworkVar( float, m_flDefuseLength ); //How long does the defuse take? Depends on if a defuser was used
|
||||
CNetworkVar( float, m_flDefuseCountDown ); //What time does the defuse complete?
|
||||
|
||||
// Control panel
|
||||
void GetControlPanelInfo( int nPanelIndex, const char *&pPanelName );
|
||||
void GetControlPanelClassName( int nPanelIndex, const char *&pPanelName );
|
||||
void SpawnControlPanels();
|
||||
|
||||
typedef CHandle<CVGuiScreen> ScreenHandle_t;
|
||||
CUtlVector<ScreenHandle_t> m_hScreens;
|
||||
|
||||
int m_iProgressBarTime;
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
//=============================================================================
|
||||
|
||||
// [tj] We need to store who planted the bomb so we can track who deserves credits for the kills
|
||||
CHandle<CCSPlayer> m_pPlanter;
|
||||
|
||||
// [tj] We need to know if this was planted by a player who recovered the bomb
|
||||
bool m_bPlantedAfterPickup;
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
};
|
||||
|
||||
extern CUtlVector< CPlantedC4* > g_PlantedC4s;
|
||||
|
||||
#endif
|
||||
|
||||
#define WEAPON_C4_CLASSNAME "weapon_c4"
|
||||
#define PLANTED_C4_CLASSNAME "planted_c4"
|
||||
|
||||
class CC4 : public CWeaponCSBase
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CC4, CWeaponCSBase );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CC4();
|
||||
virtual ~CC4();
|
||||
|
||||
virtual void Spawn();
|
||||
|
||||
bool IsPistol() const;
|
||||
void ItemPostFrame();
|
||||
virtual void PrimaryAttack();
|
||||
virtual void WeaponIdle();
|
||||
virtual void UpdateShieldState( void );
|
||||
virtual float GetMaxSpeed() const;
|
||||
|
||||
// virtual float GetSpread() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_C4; }
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
virtual bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options );
|
||||
char *GetScreenText( void );
|
||||
char m_szScreenText[32];
|
||||
|
||||
#else
|
||||
|
||||
virtual void Precache();
|
||||
virtual void GetControlPanelInfo( int nPanelIndex, const char *&pPanelName );
|
||||
virtual unsigned int PhysicsSolidMaskForEntity( void ) const;
|
||||
|
||||
virtual bool Holster( CBaseCombatWeapon *pSwitchingTo );
|
||||
virtual bool ShouldRemoveOnRoundRestart();
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [tj] Simple Setter
|
||||
//=============================================================================
|
||||
|
||||
void SetDroppedFromDeath(bool droppedFromDeath) { m_bDroppedFromDeath = droppedFromDeath; }
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
void AbortBombPlant();
|
||||
|
||||
void PlayArmingBeeps( void );
|
||||
virtual void OnPickedUp( CBaseCombatCharacter *pNewOwner );
|
||||
virtual void Drop( const Vector &vecVelocity );
|
||||
|
||||
CNetworkVar( bool, m_bStartedArming );
|
||||
CNetworkVar( float, m_fArmedTime );
|
||||
CNetworkVar( bool, m_bBombPlacedAnimation );
|
||||
|
||||
virtual bool IsRemoveable( void ) { return false; }
|
||||
|
||||
private:
|
||||
bool m_bPlayedArmingBeeps[NUM_BEEPS];
|
||||
bool m_bBombPlanted;
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [tj] we want to store if this bomb was dropped because the original owner was killed
|
||||
//=============================================================================
|
||||
|
||||
bool m_bDroppedFromDeath;
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
|
||||
private:
|
||||
|
||||
CC4( const CC4 & );
|
||||
};
|
||||
|
||||
|
||||
// All the currently-active C4 grenades.
|
||||
extern CUtlVector< CC4* > g_C4s;
|
||||
|
||||
|
||||
#endif // WEAPON_C4_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,289 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef WEAPON_CSBASE_H
|
||||
#define WEAPON_CSBASE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "cs_playeranimstate.h"
|
||||
#include "cs_weapon_parse.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CWeaponCSBase C_WeaponCSBase
|
||||
#endif
|
||||
|
||||
extern CSWeaponID AliasToWeaponID( const char *alias );
|
||||
extern const char *WeaponIDToAlias( int id );
|
||||
extern const char *GetTranslatedWeaponAlias( const char *alias);
|
||||
extern const char * GetWeaponAliasFromTranslated(const char *translatedAlias);
|
||||
extern bool IsPrimaryWeapon( CSWeaponID id );
|
||||
extern bool IsSecondaryWeapon( CSWeaponID id );
|
||||
extern int GetShellForAmmoType( const char *ammoname );
|
||||
|
||||
#define SHIELD_VIEW_MODEL "models/weapons/v_shield.mdl"
|
||||
#define SHIELD_WORLD_MODEL "models/weapons/w_shield.mdl"
|
||||
|
||||
class CCSPlayer;
|
||||
|
||||
// These are the names of the ammo types that go in the CAmmoDefs and that the
|
||||
// weapon script files reference.
|
||||
#define BULLET_PLAYER_50AE "BULLET_PLAYER_50AE"
|
||||
#define BULLET_PLAYER_762MM "BULLET_PLAYER_762MM"
|
||||
#define BULLET_PLAYER_556MM "BULLET_PLAYER_556MM"
|
||||
#define BULLET_PLAYER_556MM_BOX "BULLET_PLAYER_556MM_BOX"
|
||||
#define BULLET_PLAYER_338MAG "BULLET_PLAYER_338MAG"
|
||||
#define BULLET_PLAYER_9MM "BULLET_PLAYER_9MM"
|
||||
#define BULLET_PLAYER_BUCKSHOT "BULLET_PLAYER_BUCKSHOT"
|
||||
#define BULLET_PLAYER_45ACP "BULLET_PLAYER_45ACP"
|
||||
#define BULLET_PLAYER_357SIG "BULLET_PLAYER_357SIG"
|
||||
#define BULLET_PLAYER_57MM "BULLET_PLAYER_57MM"
|
||||
#define AMMO_TYPE_HEGRENADE "AMMO_TYPE_HEGRENADE"
|
||||
#define AMMO_TYPE_FLASHBANG "AMMO_TYPE_FLASHBANG"
|
||||
#define AMMO_TYPE_SMOKEGRENADE "AMMO_TYPE_SMOKEGRENADE"
|
||||
|
||||
#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 );
|
||||
|
||||
enum CSWeaponMode
|
||||
{
|
||||
Primary_Mode = 0,
|
||||
Secondary_Mode,
|
||||
WeaponMode_MAX
|
||||
};
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Returns the client's ID_* value for the currently owned weapon, or ID_NONE if no weapon is owned
|
||||
*/
|
||||
CSWeaponID GetClientWeaponID( bool primary );
|
||||
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
CCSWeaponInfo * GetWeaponInfo( CSWeaponID weaponID );
|
||||
|
||||
|
||||
class CWeaponCSBase : public CBaseCombatWeapon
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponCSBase, CBaseCombatWeapon );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponCSBase();
|
||||
|
||||
#ifdef GAME_DLL
|
||||
DECLARE_DATADESC();
|
||||
|
||||
virtual void CheckRespawn();
|
||||
virtual CBaseEntity* Respawn();
|
||||
|
||||
virtual const Vector& GetBulletSpread();
|
||||
virtual float GetDefaultAnimSpeed();
|
||||
|
||||
virtual void BulletWasFired( const Vector &vecStart, const Vector &vecEnd );
|
||||
virtual bool ShouldRemoveOnRoundRestart();
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [dwenger] Handle round restart processing for the weapon.
|
||||
//=============================================================================
|
||||
|
||||
virtual void OnRoundRestart();
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
virtual bool DefaultReload( int iClipSize1, int iClipSize2, int iActivity );
|
||||
|
||||
void SendReloadEvents();
|
||||
|
||||
void Materialize();
|
||||
void AttemptToMaterialize();
|
||||
virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
virtual bool IsRemoveable();
|
||||
|
||||
#endif
|
||||
|
||||
virtual bool Holster( CBaseCombatWeapon *pSwitchingTo );
|
||||
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;
|
||||
|
||||
// Pistols reset m_iShotsFired to 0 when the attack button is released.
|
||||
bool IsPistol() const;
|
||||
|
||||
virtual bool IsFullAuto() const;
|
||||
|
||||
CCSPlayer* GetPlayerOwner() const;
|
||||
|
||||
virtual float GetMaxSpeed() const; // What's the player's max speed while holding this weapon.
|
||||
|
||||
// Get CS-specific weapon data.
|
||||
CCSWeaponInfo const &GetCSWpnData() const;
|
||||
|
||||
// Get specific CS weapon ID (ie: WEAPON_AK47, etc)
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_NONE; }
|
||||
|
||||
// return true if this weapon is an instance of the given weapon type (ie: "IsA" WEAPON_GLOCK)
|
||||
bool IsA( CSWeaponID id ) const { return GetWeaponID() == id; }
|
||||
|
||||
// return true if this weapon is a kinf of the given weapon type (ie: "IsKindOf" WEAPONTYPE_RIFLE )
|
||||
bool IsKindOf( CSWeaponType type ) const { return GetCSWpnData().m_WeaponType == type; }
|
||||
|
||||
// return true if this weapon has a silencer equipped
|
||||
virtual bool IsSilenced( void ) const { return false; }
|
||||
|
||||
virtual void SetWeaponModelIndex( const char *pName );
|
||||
virtual void OnPickedUp( CBaseCombatCharacter *pNewOwner );
|
||||
|
||||
virtual void OnJump( float fImpulse );
|
||||
virtual void OnLand( float fVelocity );
|
||||
|
||||
public:
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
virtual void ProcessMuzzleFlashEvent();
|
||||
virtual bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options );
|
||||
virtual bool ShouldPredict();
|
||||
virtual void DrawCrosshair();
|
||||
virtual void OnDataChanged( DataUpdateType_t type );
|
||||
|
||||
virtual int GetMuzzleAttachment( void );
|
||||
virtual bool HideViewModelWhenZoomed( void ) { return true; }
|
||||
|
||||
float m_flCrosshairDistance;
|
||||
int m_iAmmoLastCheck;
|
||||
int m_iAlpha;
|
||||
int m_iScopeTextureID;
|
||||
int m_iCrosshairTextureID; // for white additive texture
|
||||
|
||||
virtual int GetMuzzleFlashStyle( void );
|
||||
|
||||
#else
|
||||
|
||||
virtual bool Reload();
|
||||
virtual void Spawn();
|
||||
virtual bool KeyValue( const char *szKeyName, const char *szValue );
|
||||
|
||||
virtual bool PhysicsSplash( const Vector ¢erPoint, const Vector &normal, float rawSpeed, float scaledSpeed );
|
||||
|
||||
#endif
|
||||
|
||||
bool IsUseable();
|
||||
virtual bool CanDeploy( void );
|
||||
virtual void UpdateShieldState( void );
|
||||
virtual bool SendWeaponAnim( int iActivity );
|
||||
virtual void SecondaryAttack( void );
|
||||
virtual void Precache( void );
|
||||
virtual bool CanBeSelected( void );
|
||||
virtual Activity GetDeployActivity( void );
|
||||
virtual bool DefaultDeploy( char *szViewModel, char *szWeaponModel, int iActivity, char *szAnimExt );
|
||||
virtual void DefaultTouch( CBaseEntity *pOther ); // default weapon touch
|
||||
virtual bool DefaultPistolReload();
|
||||
|
||||
virtual bool Deploy();
|
||||
virtual void Drop( const Vector &vecVelocity );
|
||||
bool PlayEmptySound();
|
||||
virtual void ItemPostFrame();
|
||||
virtual void ItemBusyFrame();
|
||||
virtual const char *GetViewModel( int viewmodelindex = 0 ) const;
|
||||
|
||||
|
||||
bool m_bDelayFire; // This variable is used to delay the time between subsequent button pressing.
|
||||
float m_flAccuracy;
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [pfreese] new accuracy model
|
||||
//=============================================================================
|
||||
|
||||
CNetworkVar( CSWeaponMode, m_weaponMode);
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
virtual float GetSpread() const;
|
||||
|
||||
virtual void UpdateAccuracyPenalty();
|
||||
|
||||
CNetworkVar( float, m_fAccuracyPenalty );
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
void SetExtraAmmoCount( int count ) { m_iExtraPrimaryAmmo = count; }
|
||||
int GetExtraAmmoCount( void ) { return m_iExtraPrimaryAmmo; }
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
//=============================================================================
|
||||
|
||||
// [tj] Accessors for the previous owner of the gun
|
||||
void SetPreviousOwner(CCSPlayer* player) { m_prevOwner = player; }
|
||||
CCSPlayer* GetPreviousOwner() { return m_prevOwner; }
|
||||
|
||||
// [tj] Accessors for the donor system
|
||||
void SetDonor(CCSPlayer* player) { m_donor = player; }
|
||||
CCSPlayer* GetDonor() { return m_donor; }
|
||||
void SetDonated(bool donated) { m_donated = true;}
|
||||
bool GetDonated() { return m_donated; }
|
||||
|
||||
//[dwenger] Accessors for the prior owner list
|
||||
void AddToPriorOwnerList(CCSPlayer* pPlayer);
|
||||
bool IsAPriorOwner(CCSPlayer* pPlayer);
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
protected:
|
||||
|
||||
float CalculateNextAttackTime( float flCycleTime );
|
||||
|
||||
private:
|
||||
|
||||
float m_flDecreaseShotsFired;
|
||||
|
||||
CWeaponCSBase( const CWeaponCSBase & );
|
||||
|
||||
int m_iExtraPrimaryAmmo;
|
||||
|
||||
float m_nextPrevOwnerTouchTime;
|
||||
CCSPlayer *m_prevOwner;
|
||||
|
||||
int m_iDefaultExtraAmmo;
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
//=============================================================================
|
||||
|
||||
// [dwenger] track all prior owners of this weapon
|
||||
CUtlVector< CCSPlayer* > m_PriorOwners;
|
||||
|
||||
// [tj] To keep track of people who drop weapons for teammates during the buy round
|
||||
CHandle<CCSPlayer> m_donor;
|
||||
bool m_donated;
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
};
|
||||
|
||||
extern ConVar weapon_accuracy_model;
|
||||
|
||||
#endif // WEAPON_CSBASE_H
|
||||
@@ -0,0 +1,218 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
#include "fx_cs_shared.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_cs_player.h"
|
||||
#else
|
||||
#include "cs_player.h"
|
||||
#endif
|
||||
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCSBaseGun, DT_WeaponCSBaseGun )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponCSBaseGun, DT_WeaponCSBaseGun )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponCSBaseGun )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_csbase_gun, CWeaponCSBaseGun );
|
||||
|
||||
|
||||
|
||||
CWeaponCSBaseGun::CWeaponCSBaseGun()
|
||||
{
|
||||
}
|
||||
|
||||
void CWeaponCSBaseGun::Spawn()
|
||||
{
|
||||
m_flAccuracy = 0.2;
|
||||
m_bDelayFire = false;
|
||||
m_zoomFullyActiveTime = -1.0f;
|
||||
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponCSBaseGun::Deploy()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return false;
|
||||
|
||||
m_flAccuracy = 0.2;
|
||||
pPlayer->m_iShotsFired = 0;
|
||||
m_bDelayFire = false;
|
||||
m_zoomFullyActiveTime = -1.0f;
|
||||
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
void CWeaponCSBaseGun::ItemPostFrame()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
//GOOSEMAN : Return zoom level back to previous zoom level before we fired a shot. This is used only for the AWP.
|
||||
// And Scout.
|
||||
if ( (m_flNextPrimaryAttack <= gpGlobals->curtime) && (pPlayer->m_bResumeZoom == TRUE) )
|
||||
{
|
||||
pPlayer->m_bResumeZoom = false;
|
||||
|
||||
if ( m_iClip1 != 0 || ( GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD ) )
|
||||
{
|
||||
m_weaponMode = Secondary_Mode;
|
||||
pPlayer->SetFOV( pPlayer, pPlayer->m_iLastZoom, 0.05f );
|
||||
m_zoomFullyActiveTime = gpGlobals->curtime + 0.05f;// Make sure we think that we are zooming on the server so we don't get instant acc bonus
|
||||
}
|
||||
}
|
||||
|
||||
BaseClass::ItemPostFrame();
|
||||
}
|
||||
|
||||
|
||||
void CWeaponCSBaseGun::PrimaryAttack()
|
||||
{
|
||||
// Derived classes should implement this and call CSBaseGunFire.
|
||||
Assert( false );
|
||||
}
|
||||
|
||||
bool CWeaponCSBaseGun::CSBaseGunFire( float flCycleTime, CSWeaponMode weaponMode )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return false;
|
||||
|
||||
const CCSWeaponInfo &pCSInfo = GetCSWpnData();
|
||||
|
||||
m_bDelayFire = true;
|
||||
|
||||
if ( m_iClip1 > 0 )
|
||||
{
|
||||
pPlayer->m_iShotsFired++;
|
||||
|
||||
// These modifications feed back into flSpread eventually.
|
||||
if ( pCSInfo.m_flAccuracyDivisor != -1 )
|
||||
{
|
||||
int iShotsFired = pPlayer->m_iShotsFired;
|
||||
|
||||
if ( pCSInfo.m_bAccuracyQuadratic )
|
||||
iShotsFired = iShotsFired * iShotsFired;
|
||||
else
|
||||
iShotsFired = iShotsFired * iShotsFired * iShotsFired;
|
||||
|
||||
m_flAccuracy = ( iShotsFired / pCSInfo.m_flAccuracyDivisor ) + pCSInfo.m_flAccuracyOffset;
|
||||
|
||||
if ( m_flAccuracy > pCSInfo.m_flMaxInaccuracy )
|
||||
m_flAccuracy = pCSInfo.m_flMaxInaccuracy;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_flAccuracy = 0;
|
||||
|
||||
if ( m_bFireOnEmpty )
|
||||
{
|
||||
PlayEmptySound();
|
||||
|
||||
// NOTE[pmf]: we don't want to actually play the dry fire animations, as most seem to depict the weapon actually firing.
|
||||
// SendWeaponAnim( ACT_VM_DRYFIRE );
|
||||
|
||||
m_bFireOnEmpty = false;
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.1f;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float flCurAttack = CalculateNextAttackTime( flCycleTime );
|
||||
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
||||
|
||||
m_iClip1--;
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
FX_FireBullets(
|
||||
pPlayer->entindex(),
|
||||
pPlayer->Weapon_ShootPosition(),
|
||||
pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
|
||||
GetWeaponID(),
|
||||
weaponMode,
|
||||
CBaseEntity::GetPredictionRandomSeed() & 255,
|
||||
GetInaccuracy(),
|
||||
GetSpread(),
|
||||
flCurAttack );
|
||||
|
||||
DoFireEffects();
|
||||
|
||||
SetWeaponIdleTime( gpGlobals->curtime + GetCSWpnData().m_flTimeToIdleAfterFire );
|
||||
|
||||
// update accuracy
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[weaponMode];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CWeaponCSBaseGun::DoFireEffects()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
|
||||
if ( pPlayer )
|
||||
pPlayer->DoMuzzleFlash();
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponCSBaseGun::Reload()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return false;
|
||||
|
||||
if (pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0)
|
||||
return false;
|
||||
|
||||
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV(), 0.0f );
|
||||
|
||||
int iResult = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
|
||||
if ( !iResult )
|
||||
return false;
|
||||
|
||||
pPlayer->SetAnimation( PLAYER_RELOAD );
|
||||
|
||||
if ((iResult) && (pPlayer->GetFOV() != pPlayer->GetDefaultFOV()))
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV() );
|
||||
}
|
||||
|
||||
m_flAccuracy = 0.2;
|
||||
pPlayer->m_iShotsFired = 0;
|
||||
m_bDelayFire = false;
|
||||
|
||||
pPlayer->SetShieldDrawnState( false );
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWeaponCSBaseGun::WeaponIdle()
|
||||
{
|
||||
if (m_flTimeWeaponIdle > gpGlobals->curtime)
|
||||
return;
|
||||
|
||||
// only idle if the slid isn't back
|
||||
if ( m_iClip1 != 0 )
|
||||
{
|
||||
SetWeaponIdleTime( gpGlobals->curtime + GetCSWpnData().m_flIdleInterval );
|
||||
SendWeaponAnim( ACT_VM_IDLE );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef WEAPON_CSBASE_GUN_H
|
||||
#define WEAPON_CSBASE_GUN_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "weapon_csbase.h"
|
||||
|
||||
|
||||
// This is the base class for pistols and rifles.
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponCSBaseGun C_WeaponCSBaseGun
|
||||
|
||||
#else
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponCSBaseGun : public CWeaponCSBase
|
||||
{
|
||||
public:
|
||||
|
||||
DECLARE_CLASS( CWeaponCSBaseGun, CWeaponCSBase );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponCSBaseGun();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
virtual void Spawn();
|
||||
virtual bool Deploy();
|
||||
virtual bool Reload();
|
||||
virtual void WeaponIdle();
|
||||
|
||||
// Derived classes call this to fire a bullet.
|
||||
bool CSBaseGunFire( float flCycleTime, CSWeaponMode weaponMode );
|
||||
|
||||
// Usually plays the shot sound. Guns with silencers can play different sounds.
|
||||
virtual void DoFireEffects();
|
||||
virtual void ItemPostFrame();
|
||||
|
||||
protected:
|
||||
float m_zoomFullyActiveTime;
|
||||
|
||||
private:
|
||||
|
||||
CWeaponCSBaseGun( const CWeaponCSBaseGun & );
|
||||
};
|
||||
|
||||
|
||||
#endif // WEAPON_CSBASE_GUN_H
|
||||
@@ -0,0 +1,235 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "decals.h"
|
||||
#include "cbase.h"
|
||||
#include "shake.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "fx_cs_shared.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CDEagle C_DEagle
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define DEAGLE_WEIGHT 7
|
||||
#define DEAGLE_MAX_CLIP 7
|
||||
|
||||
enum deagle_e {
|
||||
DEAGLE_IDLE1 = 0,
|
||||
DEAGLE_SHOOT1,
|
||||
DEAGLE_SHOOT2,
|
||||
DEAGLE_SHOOT_EMPTY,
|
||||
DEAGLE_RELOAD,
|
||||
DEAGLE_DRAW,
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CDEagle : public CWeaponCSBase
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CDEagle, CWeaponCSBase );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CDEagle();
|
||||
|
||||
void Spawn();
|
||||
|
||||
void PrimaryAttack();
|
||||
virtual bool Deploy();
|
||||
bool Reload();
|
||||
void WeaponIdle();
|
||||
void MakeBeam ();
|
||||
void BeamUpdate ();
|
||||
virtual bool UseDecrement() {return true;};
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_DEAGLE; }
|
||||
|
||||
public:
|
||||
float m_flLastFire;
|
||||
|
||||
private:
|
||||
CDEagle( const CDEagle & );
|
||||
};
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( DEagle, DT_WeaponDEagle )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CDEagle, DT_WeaponDEagle )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#if defined CLIENT_DLL
|
||||
BEGIN_PREDICTION_DATA( CDEagle )
|
||||
DEFINE_FIELD( m_flLastFire, FIELD_FLOAT ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_deagle, CDEagle );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_deagle );
|
||||
|
||||
|
||||
|
||||
CDEagle::CDEagle()
|
||||
{
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
|
||||
void CDEagle::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
m_flAccuracy = 0.9;
|
||||
}
|
||||
|
||||
|
||||
bool CDEagle::Deploy()
|
||||
{
|
||||
m_flAccuracy = 0.9;
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
float CDEagle::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 1.5f * (1 - m_flAccuracy);
|
||||
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
return 0.25f * (1 - m_flAccuracy);
|
||||
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
return 0.115f * (1 - m_flAccuracy);
|
||||
|
||||
else
|
||||
return 0.13f * (1 - m_flAccuracy);
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CDEagle::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
// Mark the time of this shot and determine the accuracy modifier based on the last shot fired...
|
||||
m_flAccuracy -= (0.35)*(0.4 - ( gpGlobals->curtime - m_flLastFire ) );
|
||||
|
||||
if (m_flAccuracy > 0.9)
|
||||
m_flAccuracy = 0.9;
|
||||
else if (m_flAccuracy < 0.55)
|
||||
m_flAccuracy = 0.55;
|
||||
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
|
||||
if (m_iClip1 <= 0)
|
||||
{
|
||||
if ( m_bFireOnEmpty )
|
||||
{
|
||||
PlayEmptySound();
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.1f;
|
||||
m_bFireOnEmpty = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pPlayer->m_iShotsFired++;
|
||||
|
||||
m_iClip1--;
|
||||
|
||||
pPlayer->DoMuzzleFlash();
|
||||
|
||||
if( m_iClip1 > 0 )
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
||||
else
|
||||
SendWeaponAnim( ACT_VM_DRYFIRE );
|
||||
|
||||
//SetPlayerShieldAnim();
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
//pPlayer->m_iWeaponVolume = BIG_EXPLOSION_VOLUME;
|
||||
//pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH;
|
||||
|
||||
FX_FireBullets(
|
||||
pPlayer->entindex(),
|
||||
pPlayer->Weapon_ShootPosition(),
|
||||
pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
|
||||
GetWeaponID(),
|
||||
Primary_Mode,
|
||||
CBaseEntity::GetPredictionRandomSeed() & 255,
|
||||
GetInaccuracy(),
|
||||
GetSpread());
|
||||
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + GetCSWpnData().m_flCycleTime;
|
||||
|
||||
if ( !m_iClip1 && pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0 )
|
||||
{
|
||||
// HEV suit - indicate out of ammo condition
|
||||
pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0);
|
||||
}
|
||||
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 1.8 );
|
||||
|
||||
// update accuracy
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[Primary_Mode];
|
||||
|
||||
QAngle punchAngle = pPlayer->GetPunchAngle();
|
||||
punchAngle.x -= 2;
|
||||
pPlayer->SetPunchAngle( punchAngle );
|
||||
|
||||
//ResetPlayerShieldAnim();
|
||||
}
|
||||
|
||||
|
||||
bool CDEagle::Reload()
|
||||
{
|
||||
if ( !DefaultPistolReload() )
|
||||
return false;
|
||||
|
||||
m_flAccuracy = 0.9;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDEagle::WeaponIdle()
|
||||
{
|
||||
if ( m_flTimeWeaponIdle > gpGlobals->curtime )
|
||||
return;
|
||||
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 20 );
|
||||
|
||||
if (m_iClip1 != 0)
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_IDLE );
|
||||
}
|
||||
|
||||
//if ( FBitSet(m_iWeaponState, WPNSTATE_SHIELD_DRAWN) )
|
||||
// SendWeaponAnim( SHIELDGUN_DRAWN_IDLE, UseDecrement() ? 1:0 );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,317 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "fx_cs_shared.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponElite C_WeaponElite
|
||||
#include "c_cs_player.h"
|
||||
#include "c_te_effect_dispatch.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponElite : public CWeaponCSBase
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponElite, CWeaponCSBase );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponElite();
|
||||
|
||||
virtual void Spawn();
|
||||
virtual void Precache();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
virtual bool Deploy();
|
||||
|
||||
virtual bool Reload();
|
||||
|
||||
virtual void WeaponIdle();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_ELITE; }
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
virtual int GetMuzzleAttachment( void );
|
||||
virtual bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options );
|
||||
#endif
|
||||
|
||||
virtual const char *GetWorldModel( void ) const;
|
||||
virtual int GetWorldModelIndex( void );
|
||||
|
||||
protected:
|
||||
bool FiringLeft() const;
|
||||
|
||||
private:
|
||||
|
||||
CWeaponElite( const CWeaponElite & );
|
||||
float m_flLastFire;
|
||||
|
||||
int m_droppedModelIndex;
|
||||
bool m_inPrecache;
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponElite, DT_WeaponElite )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponElite, DT_WeaponElite )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#if defined CLIENT_DLL
|
||||
BEGIN_PREDICTION_DATA( CWeaponElite )
|
||||
DEFINE_FIELD( m_flLastFire, FIELD_FLOAT ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_elite, CWeaponElite );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_elite );
|
||||
|
||||
CWeaponElite::CWeaponElite()
|
||||
{
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
m_inPrecache = false;
|
||||
}
|
||||
|
||||
|
||||
void CWeaponElite::Spawn( )
|
||||
{
|
||||
m_flAccuracy = 0.88;
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
|
||||
void CWeaponElite::Precache()
|
||||
{
|
||||
m_inPrecache = true;
|
||||
BaseClass::Precache();
|
||||
|
||||
PrecacheModel( "models/weapons/w_eq_eholster_elite.mdl" );
|
||||
PrecacheModel( "models/weapons/w_eq_eholster.mdl" );
|
||||
PrecacheModel( "models/weapons/w_pist_elite_single.mdl" );
|
||||
m_droppedModelIndex = CBaseEntity::PrecacheModel( GetCSWpnData().m_szDroppedModel );
|
||||
m_inPrecache = false;
|
||||
}
|
||||
|
||||
bool CWeaponElite::Deploy( )
|
||||
{
|
||||
m_flAccuracy = 0.88;
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
int CWeaponElite::GetWorldModelIndex( void )
|
||||
{
|
||||
if ( GetOwner() || m_inPrecache )
|
||||
{
|
||||
return m_iWorldModelIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_droppedModelIndex;
|
||||
}
|
||||
}
|
||||
|
||||
const char * CWeaponElite::GetWorldModel( void ) const
|
||||
{
|
||||
if ( GetOwner() || m_inPrecache )
|
||||
{
|
||||
return BaseClass::GetWorldModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetCSWpnData().m_szDroppedModel;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponElite::FiringLeft() const
|
||||
{
|
||||
// fire left-hand gun with even number of bullets left
|
||||
return (m_iClip1 & 1) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
float CWeaponElite::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 1.3f * (1 - m_flAccuracy);
|
||||
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
return 0.175f * (1 - m_flAccuracy);
|
||||
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
return 0.08f * (1 - m_flAccuracy);
|
||||
|
||||
else
|
||||
return 0.1f * (1 - m_flAccuracy);
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CWeaponElite::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
// Mark the time of this shot and determine the accuracy modifier based on the last shot fired...
|
||||
m_flAccuracy -= (0.275)*(0.325 - (gpGlobals->curtime - m_flLastFire));
|
||||
|
||||
if (m_flAccuracy > 0.88)
|
||||
m_flAccuracy = 0.88;
|
||||
else if (m_flAccuracy < 0.55)
|
||||
m_flAccuracy = 0.55;
|
||||
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
|
||||
if (m_iClip1 <= 0)
|
||||
{
|
||||
if ( m_bFireOnEmpty )
|
||||
{
|
||||
PlayEmptySound();
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.1f;
|
||||
m_bFireOnEmpty = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pPlayer->m_iShotsFired++;
|
||||
|
||||
m_iClip1--;
|
||||
|
||||
pPlayer->DoMuzzleFlash();
|
||||
|
||||
//SetPlayerShieldAnim();
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
FX_FireBullets(
|
||||
pPlayer->entindex(),
|
||||
pPlayer->Weapon_ShootPosition(),
|
||||
pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
|
||||
GetWeaponID(),
|
||||
FiringLeft() ? Secondary_Mode : Primary_Mode,
|
||||
CBaseEntity::GetPredictionRandomSeed() & 255,
|
||||
GetInaccuracy(),
|
||||
GetSpread());
|
||||
|
||||
m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + GetCSWpnData().m_flCycleTime;
|
||||
|
||||
if (!m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0)
|
||||
{
|
||||
// HEV suit - indicate out of ammo condition
|
||||
pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0);
|
||||
}
|
||||
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 2.5 );
|
||||
|
||||
if ( FiringLeft() )
|
||||
{
|
||||
if ( m_iClip1 > 0 )
|
||||
SendWeaponAnim( ACT_VM_SECONDARYATTACK );
|
||||
else
|
||||
SendWeaponAnim( ACT_VM_DRYFIRE );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_iClip1 > 1 )
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
||||
else
|
||||
SendWeaponAnim( ACT_VM_DRYFIRE_LEFT );
|
||||
}
|
||||
|
||||
// update accuracy
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[Primary_Mode];
|
||||
|
||||
QAngle punchAngle = pPlayer->GetPunchAngle();
|
||||
punchAngle.x -= 2;
|
||||
pPlayer->SetPunchAngle( punchAngle );
|
||||
|
||||
//ResetPlayerShieldAnim();
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponElite::Reload()
|
||||
{
|
||||
if ( !DefaultPistolReload() )
|
||||
return false;
|
||||
|
||||
m_flAccuracy = 0.88;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWeaponElite::WeaponIdle()
|
||||
{
|
||||
if (m_flTimeWeaponIdle > gpGlobals->curtime)
|
||||
return;
|
||||
|
||||
/*
|
||||
// switching to the idle with the slide back on the right pistol causes animation pops transitioning
|
||||
// from/to the depot/holster animations. The pop transition to the reload is less noticeable, so
|
||||
// we'll live with that one
|
||||
|
||||
if ( m_iClip1 == 1 )
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_IDLE_EMPTY_LEFT );
|
||||
}
|
||||
*/
|
||||
|
||||
// only idle if either slide isn't back
|
||||
if ( m_iClip1 >= 2 )
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_IDLE );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
bool CWeaponElite::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
|
||||
{
|
||||
if( event == 5001 )
|
||||
{
|
||||
C_CSPlayer *pPlayer = ToCSPlayer( GetOwner() );
|
||||
if( pPlayer && pPlayer->GetFOV() < pPlayer->GetDefaultFOV() && HideViewModelWhenZoomed() )
|
||||
return true;
|
||||
|
||||
CEffectData data;
|
||||
data.m_fFlags = 0;
|
||||
data.m_hEntity = pViewModel->GetRefEHandle();
|
||||
data.m_nAttachmentIndex = FiringLeft() ? 1 : 2; // toggle muzzle flash
|
||||
data.m_flScale = GetCSWpnData().m_flMuzzleScale;
|
||||
|
||||
DispatchEffect( "CS_MuzzleFlash", data );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return BaseClass::OnFireEvent( pViewModel, origin, angles, event, options );
|
||||
}
|
||||
|
||||
int CWeaponElite::GetMuzzleAttachment( void )
|
||||
{
|
||||
return LookupAttachment( FiringLeft() ? "muzzle_flash_l" : "muzzle_flash_r" );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
#include "fx_cs_shared.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponFamas C_WeaponFamas
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponFamas : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponFamas, CWeaponCSBase );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponFamas();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
virtual void SecondaryAttack();
|
||||
virtual bool Deploy();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual void ItemPostFrame();
|
||||
|
||||
void FamasFire( float flSpread, bool bFireBurst );
|
||||
void FireRemaining();
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_FAMAS; }
|
||||
|
||||
private:
|
||||
|
||||
CWeaponFamas( const CWeaponFamas & );
|
||||
CNetworkVar( bool, m_bBurstMode );
|
||||
CNetworkVar( int, m_iBurstShotsRemaining );
|
||||
float m_fNextBurstShot; // time to shoot the next bullet in burst fire mode
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponFamas, DT_WeaponFamas )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponFamas, DT_WeaponFamas )
|
||||
#ifdef CLIENT_DLL
|
||||
RecvPropBool( RECVINFO( m_bBurstMode ) ),
|
||||
RecvPropInt( RECVINFO( m_iBurstShotsRemaining ) ),
|
||||
#else
|
||||
SendPropBool( SENDINFO( m_bBurstMode ) ),
|
||||
SendPropInt( SENDINFO( m_iBurstShotsRemaining ) ),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#if defined(CLIENT_DLL)
|
||||
BEGIN_PREDICTION_DATA( CWeaponFamas )
|
||||
DEFINE_PRED_FIELD( m_iBurstShotsRemaining, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_fNextBurstShot, FIELD_FLOAT, 0 ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_famas, CWeaponFamas );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_famas );
|
||||
|
||||
|
||||
const float kFamasBurstCycleTime = 0.075f;
|
||||
|
||||
|
||||
CWeaponFamas::CWeaponFamas()
|
||||
{
|
||||
m_bBurstMode = false;
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponFamas::Deploy( )
|
||||
{
|
||||
m_iBurstShotsRemaining = 0;
|
||||
m_fNextBurstShot = 0.0f;
|
||||
m_flAccuracy = 0.9f;
|
||||
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
|
||||
// Secondary attack could be three-round burst mode
|
||||
void CWeaponFamas::SecondaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( m_bBurstMode )
|
||||
{
|
||||
ClientPrint( pPlayer, HUD_PRINTCENTER, "#Switch_To_FullAuto" );
|
||||
m_bBurstMode = false;
|
||||
m_weaponMode = Primary_Mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClientPrint( pPlayer, HUD_PRINTCENTER, "#Switch_To_BurstFire" );
|
||||
m_bBurstMode = true;
|
||||
m_weaponMode = Secondary_Mode;
|
||||
}
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 0.3;
|
||||
}
|
||||
|
||||
float CWeaponFamas::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
float fAutoPenalty = m_bBurstMode ? 0.0f : 0.01f;
|
||||
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) ) // if player is in air
|
||||
return 0.03f + 0.3f * m_flAccuracy + fAutoPenalty;
|
||||
|
||||
else if ( pPlayer->GetAbsVelocity().Length2D() > 140 ) // if player is moving
|
||||
return 0.03f + 0.07f * m_flAccuracy + fAutoPenalty;
|
||||
/* new code */
|
||||
else
|
||||
return 0.02f * m_flAccuracy + fAutoPenalty;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
|
||||
void CWeaponFamas::ItemPostFrame()
|
||||
{
|
||||
if ( m_iBurstShotsRemaining > 0 && gpGlobals->curtime >= m_fNextBurstShot )
|
||||
FireRemaining();
|
||||
|
||||
BaseClass::ItemPostFrame();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// GOOSEMAN : FireRemaining used by Glock18
|
||||
void CWeaponFamas::FireRemaining()
|
||||
{
|
||||
m_iClip1--;
|
||||
|
||||
if (m_iClip1 < 0)
|
||||
{
|
||||
m_iClip1 = 0;
|
||||
m_iBurstShotsRemaining = 0;
|
||||
m_fNextBurstShot = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
Error( "!pPlayer" );
|
||||
|
||||
// Famas burst mode
|
||||
FX_FireBullets(
|
||||
pPlayer->entindex(),
|
||||
pPlayer->Weapon_ShootPosition(),
|
||||
pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
|
||||
GetWeaponID(),
|
||||
Secondary_Mode,
|
||||
CBaseEntity::GetPredictionRandomSeed() & 255,
|
||||
GetInaccuracy(),
|
||||
GetSpread(),
|
||||
m_fNextBurstShot);
|
||||
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
||||
|
||||
pPlayer->DoMuzzleFlash();
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
pPlayer->m_iShotsFired++;
|
||||
|
||||
--m_iBurstShotsRemaining;
|
||||
if ( m_iBurstShotsRemaining > 0 )
|
||||
m_fNextBurstShot += kFamasBurstCycleTime;
|
||||
else
|
||||
m_fNextBurstShot = 0.0f;
|
||||
|
||||
// update accuracy
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[Secondary_Mode];
|
||||
}
|
||||
|
||||
|
||||
void CWeaponFamas::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
// don't fire underwater
|
||||
if (pPlayer->GetWaterLevel() == 3)
|
||||
{
|
||||
PlayEmptySound( );
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.15;
|
||||
return;
|
||||
}
|
||||
|
||||
pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
float flCycleTime = GetCSWpnData().m_flCycleTime;
|
||||
|
||||
// change a few things if we're in burst mode
|
||||
if ( m_bBurstMode )
|
||||
{
|
||||
flCycleTime = 0.55f;
|
||||
m_iBurstShotsRemaining = 2;
|
||||
m_fNextBurstShot = gpGlobals->curtime + kFamasBurstCycleTime;
|
||||
}
|
||||
|
||||
if ( !CSBaseGunFire( flCycleTime, m_weaponMode ) )
|
||||
return;
|
||||
|
||||
if ( pPlayer->GetAbsVelocity().Length2D() > 5 )
|
||||
pPlayer->KickBack ( 1, 0.45, 0.275, 0.05, 4, 2.5, 7 );
|
||||
|
||||
else if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
pPlayer->KickBack ( 1.25, 0.45, 0.22, 0.18, 5.5, 4, 5 );
|
||||
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
pPlayer->KickBack ( 0.575, 0.325, 0.2, 0.011, 3.25, 2, 8 );
|
||||
|
||||
else
|
||||
pPlayer->KickBack ( 0.625, 0.375, 0.25, 0.0125, 3.5, 2.25, 8 );
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "fx_cs_shared.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponFiveSeven C_WeaponFiveSeven
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponFiveSeven : public CWeaponCSBase
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponFiveSeven, CWeaponCSBase );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponFiveSeven();
|
||||
|
||||
virtual void Spawn();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
virtual void SecondaryAttack();
|
||||
virtual bool Deploy();
|
||||
|
||||
virtual bool Reload();
|
||||
|
||||
virtual void WeaponIdle();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_FIVESEVEN; }
|
||||
|
||||
private:
|
||||
|
||||
CWeaponFiveSeven( const CWeaponFiveSeven & );
|
||||
|
||||
float m_flLastFire;
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponFiveSeven, DT_WeaponFiveSeven )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponFiveSeven, DT_WeaponFiveSeven )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#if defined CLIENT_DLL
|
||||
BEGIN_PREDICTION_DATA( CWeaponFiveSeven )
|
||||
DEFINE_FIELD( m_flLastFire, FIELD_FLOAT ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_fiveseven, CWeaponFiveSeven );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_fiveseven );
|
||||
|
||||
|
||||
|
||||
CWeaponFiveSeven::CWeaponFiveSeven()
|
||||
{
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
|
||||
void CWeaponFiveSeven::Spawn( )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
|
||||
m_flAccuracy = 0.92;
|
||||
}
|
||||
|
||||
bool CWeaponFiveSeven::Deploy()
|
||||
{
|
||||
m_flAccuracy = 0.92;
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
|
||||
float CWeaponFiveSeven::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 1.5f * (1 - m_flAccuracy);
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
return 0.255f * (1 - m_flAccuracy);
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
return 0.075f * (1 - m_flAccuracy);
|
||||
else
|
||||
return 0.15f * (1 - m_flAccuracy);
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CWeaponFiveSeven::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
// Mark the time of this shot and determine the accuracy modifier based on the last shot fired...
|
||||
m_flAccuracy -= (0.25)*(0.275 - (gpGlobals->curtime - m_flLastFire));
|
||||
|
||||
if (m_flAccuracy > 0.92)
|
||||
m_flAccuracy = 0.92;
|
||||
else if (m_flAccuracy < 0.725)
|
||||
m_flAccuracy = 0.725;
|
||||
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
|
||||
if (m_iClip1 <= 0)
|
||||
{
|
||||
if ( m_bFireOnEmpty )
|
||||
{
|
||||
PlayEmptySound();
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.1f;
|
||||
m_bFireOnEmpty = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pPlayer->m_iShotsFired++;
|
||||
|
||||
m_iClip1--;
|
||||
pPlayer->DoMuzzleFlash();
|
||||
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
|
||||
FX_FireBullets(
|
||||
pPlayer->entindex(),
|
||||
pPlayer->Weapon_ShootPosition(),
|
||||
pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
|
||||
GetWeaponID(),
|
||||
Primary_Mode,
|
||||
CBaseEntity::GetPredictionRandomSeed() & 255,
|
||||
GetInaccuracy(),
|
||||
GetSpread());
|
||||
|
||||
m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + GetCSWpnData().m_flCycleTime;
|
||||
|
||||
if (!m_iClip1 && pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0)
|
||||
{
|
||||
// HEV suit - indicate out of ammo condition
|
||||
pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0);
|
||||
}
|
||||
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 2 );
|
||||
|
||||
// update accuracy
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[Primary_Mode];
|
||||
|
||||
QAngle angle = pPlayer->GetPunchAngle();
|
||||
angle.x -= 2;
|
||||
pPlayer->SetPunchAngle( angle );
|
||||
}
|
||||
|
||||
|
||||
void CWeaponFiveSeven::SecondaryAttack()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponFiveSeven::Reload()
|
||||
{
|
||||
if ( !DefaultPistolReload() )
|
||||
return false;
|
||||
|
||||
m_flAccuracy = 0.92;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWeaponFiveSeven::WeaponIdle()
|
||||
{
|
||||
if (m_flTimeWeaponIdle > gpGlobals->curtime)
|
||||
return;
|
||||
|
||||
// only idle if the slid isn't back
|
||||
if (m_iClip1 != 0)
|
||||
{
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 4 );
|
||||
SendWeaponAnim( ACT_VM_IDLE );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "gamerules.h"
|
||||
#include "npcevent.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "weapon_flashbang.h"
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
#include "items.h"
|
||||
#include "flashbang_projectile.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define GRENADE_TIMER 3.0f //Seconds
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( Flashbang, DT_Flashbang )
|
||||
|
||||
BEGIN_NETWORK_TABLE(CFlashbang, DT_Flashbang)
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CFlashbang )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_flashbang, CFlashbang );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_flashbang );
|
||||
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
BEGIN_DATADESC( CFlashbang )
|
||||
END_DATADESC()
|
||||
|
||||
void CFlashbang::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer )
|
||||
{
|
||||
CFlashbangProjectile::Create(
|
||||
vecSrc,
|
||||
vecAngles,
|
||||
vecVel,
|
||||
angImpulse,
|
||||
pPlayer );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef WEAPON_FLASHBANG_H
|
||||
#define WEAPON_FLASHBANG_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "weapon_basecsgrenade.h"
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CFlashbang C_Flashbang
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Fragmentation grenades
|
||||
//-----------------------------------------------------------------------------
|
||||
class CFlashbang : public CBaseCSGrenade
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CFlashbang, CBaseCSGrenade );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CFlashbang() {}
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_FLASHBANG; }
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#else
|
||||
DECLARE_DATADESC();
|
||||
|
||||
virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer );
|
||||
#endif
|
||||
|
||||
CFlashbang( const CFlashbang & ) {}
|
||||
};
|
||||
|
||||
|
||||
#endif // WEAPON_FLASHBANG_H
|
||||
@@ -0,0 +1,213 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponG3SG1 C_WeaponG3SG1
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
#include "KeyValues.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponG3SG1 : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponG3SG1, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponG3SG1();
|
||||
|
||||
virtual void Spawn();
|
||||
virtual void SecondaryAttack();
|
||||
virtual void PrimaryAttack();
|
||||
virtual bool Reload();
|
||||
virtual bool Deploy();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
virtual float GetMaxSpeed();
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_G3SG1; }
|
||||
|
||||
private:
|
||||
CWeaponG3SG1( const CWeaponG3SG1 & );
|
||||
|
||||
float m_flLastFire;
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponG3SG1, DT_WeaponG3SG1 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponG3SG1, DT_WeaponG3SG1 )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#if defined CLIENT_DLL
|
||||
BEGIN_PREDICTION_DATA( CWeaponG3SG1 )
|
||||
DEFINE_FIELD( m_flLastFire, FIELD_FLOAT ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_g3sg1, CWeaponG3SG1 );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_g3sg1 );
|
||||
|
||||
|
||||
|
||||
CWeaponG3SG1::CWeaponG3SG1()
|
||||
{
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
void CWeaponG3SG1::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
m_flAccuracy = 0.98;
|
||||
}
|
||||
|
||||
|
||||
void CWeaponG3SG1::SecondaryAttack()
|
||||
{
|
||||
const float kZoomTime = 0.10f;
|
||||
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( pPlayer->GetFOV() == pPlayer->GetDefaultFOV() )
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, 40, kZoomTime );
|
||||
m_weaponMode = Secondary_Mode;
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyAltSwitch;
|
||||
}
|
||||
else if (pPlayer->GetFOV() == 40)
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, 15, kZoomTime );
|
||||
m_weaponMode = Secondary_Mode;
|
||||
}
|
||||
else if (pPlayer->GetFOV() == 15)
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV(), kZoomTime );
|
||||
m_weaponMode = Primary_Mode;
|
||||
}
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// If this isn't guarded, the sound will be emitted twice, once by the server and once by the client.
|
||||
// Let the server play it since if only the client plays it, it's liable to get played twice cause of
|
||||
// a prediction error. joy.
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [tj] Playing this from the player so that we don't try to play the sound outside the level.
|
||||
//=============================================================================
|
||||
if ( GetPlayerOwner() )
|
||||
{
|
||||
GetPlayerOwner()->EmitSound( "Default.Zoom" ); // zoom sound
|
||||
}
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
// let the bots hear the rifle zoom
|
||||
IGameEvent * event = gameeventmanager->CreateEvent( "weapon_zoom" );
|
||||
if( event )
|
||||
{
|
||||
event->SetInt( "userid", pPlayer->GetUserID() );
|
||||
gameeventmanager->FireEvent( event );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 0.3f;
|
||||
m_zoomFullyActiveTime = gpGlobals->curtime + 0.3; // The worst zoom time from above.
|
||||
}
|
||||
|
||||
float CWeaponG3SG1::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
float fSpread = 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
fSpread = 0.45f * (1.0f - m_flAccuracy);
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
fSpread = 0.15f;
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
fSpread = 0.035f * (1.0f - m_flAccuracy);
|
||||
else
|
||||
fSpread = 0.055f * (1.0f - m_flAccuracy);
|
||||
|
||||
// If we are not zoomed in, or we have very recently zoomed and are still transitioning, the bullet diverts more.
|
||||
if (pPlayer->GetFOV() == pPlayer->GetDefaultFOV() || (gpGlobals->curtime < m_zoomFullyActiveTime))
|
||||
fSpread += 0.025;
|
||||
|
||||
return fSpread;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CWeaponG3SG1::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
// Mark the time of this shot and determine the accuracy modifier based on the last shot fired...
|
||||
m_flAccuracy = 0.55 + (0.3) * (gpGlobals->curtime - m_flLastFire);
|
||||
|
||||
if (m_flAccuracy > 0.98)
|
||||
m_flAccuracy = 0.98;
|
||||
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
|
||||
if ( !CSBaseGunFire( GetCSWpnData().m_flCycleTime, m_weaponMode ) )
|
||||
return;
|
||||
|
||||
// Adjust the punch angle.
|
||||
QAngle angle = pPlayer->GetPunchAngle();
|
||||
angle.x -= SharedRandomFloat("G3SG1PunchAngleX", 0.75, 1.75 ) + ( angle.x / 4 );
|
||||
angle.y += SharedRandomFloat("G3SG1PunchAngleY", -0.75, 0.75 );
|
||||
pPlayer->SetPunchAngle( angle );
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponG3SG1::Reload()
|
||||
{
|
||||
bool ret = BaseClass::Reload();
|
||||
|
||||
m_flAccuracy = 0.98;
|
||||
m_weaponMode = Primary_Mode;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CWeaponG3SG1::Deploy()
|
||||
{
|
||||
bool ret = BaseClass::Deploy();
|
||||
|
||||
m_flAccuracy = 0.98;
|
||||
m_weaponMode = Primary_Mode;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
float CWeaponG3SG1::GetMaxSpeed()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( pPlayer && pPlayer->GetFOV() == pPlayer->GetDefaultFOV() )
|
||||
return BaseClass::GetMaxSpeed();
|
||||
else
|
||||
return 150; // zoomed in
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponGalil C_WeaponGalil
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponGalil : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponGalil, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponGalil();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_GALIL; }
|
||||
|
||||
private:
|
||||
|
||||
CWeaponGalil( const CWeaponGalil & );
|
||||
|
||||
void GalilFire( float flSpread );
|
||||
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponGalil, DT_WeaponGalil )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponGalil, DT_WeaponGalil )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponGalil )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_galil, CWeaponGalil );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_galil );
|
||||
|
||||
|
||||
|
||||
CWeaponGalil::CWeaponGalil()
|
||||
{
|
||||
}
|
||||
|
||||
float CWeaponGalil::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 0.04f + 0.3f * m_flAccuracy;
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 140)
|
||||
return 0.04f + 0.07f * m_flAccuracy;
|
||||
else
|
||||
return 0.0375f * m_flAccuracy;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CWeaponGalil::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
// don't fire underwater
|
||||
if (pPlayer->GetWaterLevel() == 3)
|
||||
{
|
||||
PlayEmptySound( );
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.15;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !CSBaseGunFire( GetCSWpnData().m_flCycleTime, Primary_Mode ) )
|
||||
return;
|
||||
|
||||
// CSBaseGunFire can kill us, forcing us to drop our weapon, if we shoot something that explodes
|
||||
pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
pPlayer->KickBack (1.0, 0.45, 0.28, 0.045, 3.75, 3, 7);
|
||||
else if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
pPlayer->KickBack (1.2, 0.5, 0.23, 0.15, 5.5, 3.5, 6);
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
pPlayer->KickBack (0.6, 0.3, 0.2, 0.0125, 3.25, 2, 7);
|
||||
else
|
||||
pPlayer->KickBack (0.65, 0.35, 0.25, 0.015, 3.5, 2.25, 7);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,369 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "fx_cs_shared.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponGlock C_WeaponGlock
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponGlock : public CWeaponCSBase
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponGlock, CWeaponCSBase );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponGlock();
|
||||
|
||||
virtual void Spawn();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
virtual void SecondaryAttack();
|
||||
virtual bool Deploy();
|
||||
|
||||
virtual void ItemPostFrame();
|
||||
|
||||
void GlockFire( float fSpread, bool bFireBurst );
|
||||
void FireRemaining( float fSpread );
|
||||
|
||||
virtual bool Reload();
|
||||
|
||||
virtual void WeaponIdle();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_GLOCK; }
|
||||
|
||||
private:
|
||||
|
||||
CWeaponGlock( const CWeaponGlock & );
|
||||
|
||||
CNetworkVar( bool, m_bBurstMode );
|
||||
CNetworkVar( int, m_iBurstShotsRemaining ); // used to keep track of the shots fired during the Glock18 burst fire mode.
|
||||
float m_fNextBurstShot; // time to shoot the next bullet in burst fire mode
|
||||
float m_flLastFire;
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponGlock, DT_WeaponGlock )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponGlock, DT_WeaponGlock )
|
||||
#ifdef CLIENT_DLL
|
||||
RecvPropBool( RECVINFO( m_bBurstMode ) ),
|
||||
RecvPropInt( RECVINFO( m_iBurstShotsRemaining ) ),
|
||||
#else
|
||||
SendPropBool( SENDINFO( m_bBurstMode ) ),
|
||||
SendPropInt( SENDINFO( m_iBurstShotsRemaining ) ),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#if defined(CLIENT_DLL)
|
||||
BEGIN_PREDICTION_DATA( CWeaponGlock )
|
||||
DEFINE_FIELD( m_flLastFire, FIELD_FLOAT ),
|
||||
DEFINE_PRED_FIELD( m_iBurstShotsRemaining, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_fNextBurstShot, FIELD_FLOAT, 0 ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_glock, CWeaponGlock );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_glock );
|
||||
|
||||
const float kGlockBurstCycleTime = 0.06f;
|
||||
|
||||
CWeaponGlock::CWeaponGlock()
|
||||
{
|
||||
m_bBurstMode = false;
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
m_iBurstShotsRemaining = 0;
|
||||
m_fNextBurstShot = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
void CWeaponGlock::Spawn( )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
|
||||
m_bBurstMode = false;
|
||||
m_iBurstShotsRemaining = 0;
|
||||
m_fNextBurstShot = 0.0f;
|
||||
m_flAccuracy = 0.9f;
|
||||
}
|
||||
|
||||
bool CWeaponGlock::Deploy( )
|
||||
{
|
||||
m_iBurstShotsRemaining = 0;
|
||||
m_fNextBurstShot = 0.0f;
|
||||
m_flAccuracy = 0.9f;
|
||||
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
void CWeaponGlock::SecondaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( m_bBurstMode )
|
||||
{
|
||||
ClientPrint( pPlayer, HUD_PRINTCENTER, "#Switch_To_SemiAuto" );
|
||||
m_bBurstMode = false;
|
||||
m_weaponMode = Primary_Mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClientPrint( pPlayer, HUD_PRINTCENTER, "#Switch_To_BurstFire" );
|
||||
m_bBurstMode = true;
|
||||
m_weaponMode = Secondary_Mode;
|
||||
}
|
||||
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 0.3;
|
||||
}
|
||||
|
||||
float CWeaponGlock::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( m_bBurstMode )
|
||||
{
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 1.2f * (1 - m_flAccuracy);
|
||||
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
return 0.185f * (1 - m_flAccuracy);
|
||||
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
return 0.095f * (1 - m_flAccuracy);
|
||||
|
||||
else
|
||||
return 0.3f * (1 - m_flAccuracy);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 1.0f * (1 - m_flAccuracy);
|
||||
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
return 0.165f * (1 - m_flAccuracy);
|
||||
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
return 0.075f * (1 - m_flAccuracy);
|
||||
|
||||
else
|
||||
return 0.1f * (1 - m_flAccuracy);
|
||||
}
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
|
||||
void CWeaponGlock::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
float flCycleTime = m_bBurstMode ? 0.5f : GetCSWpnData().m_flCycleTime;
|
||||
|
||||
// Mark the time of this shot and determine the accuracy modifier based on the last shot fired...
|
||||
m_flAccuracy -= (0.275)*(0.325 - (gpGlobals->curtime - m_flLastFire));
|
||||
|
||||
if (m_flAccuracy > 0.9)
|
||||
m_flAccuracy = 0.9;
|
||||
else if (m_flAccuracy < 0.6)
|
||||
m_flAccuracy = 0.6;
|
||||
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
|
||||
if (m_iClip1 <= 0)
|
||||
{
|
||||
if ( m_bFireOnEmpty )
|
||||
|
||||
{
|
||||
PlayEmptySound();
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.1f;
|
||||
m_bFireOnEmpty = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pPlayer->m_iShotsFired++;
|
||||
|
||||
m_iClip1--;
|
||||
|
||||
pPlayer->DoMuzzleFlash();
|
||||
|
||||
//SetPlayerShieldAnim();
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
// non-silenced
|
||||
//pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
|
||||
//pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
|
||||
|
||||
FX_FireBullets(
|
||||
pPlayer->entindex(),
|
||||
pPlayer->Weapon_ShootPosition(),
|
||||
pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
|
||||
GetWeaponID(),
|
||||
Primary_Mode,
|
||||
CBaseEntity::GetPredictionRandomSeed() & 255, // wrap it for network traffic so it's the same between client and server
|
||||
GetInaccuracy(),
|
||||
GetSpread(),
|
||||
gpGlobals->curtime);
|
||||
|
||||
m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + flCycleTime;
|
||||
|
||||
if (!m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0)
|
||||
{
|
||||
// HEV suit - indicate out of ammo condition
|
||||
pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0);
|
||||
}
|
||||
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 2.5f );
|
||||
|
||||
if ( m_bBurstMode )
|
||||
{
|
||||
// Fire off the next two rounds
|
||||
m_fNextBurstShot = gpGlobals->curtime + kGlockBurstCycleTime;
|
||||
m_iBurstShotsRemaining = 2;
|
||||
|
||||
SendWeaponAnim( ACT_VM_SECONDARYATTACK );
|
||||
}
|
||||
else
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
||||
}
|
||||
|
||||
// update accuracy
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[m_weaponMode];
|
||||
|
||||
//ResetPlayerShieldAnim();
|
||||
}
|
||||
|
||||
|
||||
// GOOSEMAN : FireRemaining used by Glock18
|
||||
|
||||
void CWeaponGlock::FireRemaining( float fSpread )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
Error( "!pPlayer" );
|
||||
|
||||
if ( m_iBurstShotsRemaining == 0 )
|
||||
return;
|
||||
|
||||
if (m_iClip1 <= 0)
|
||||
{
|
||||
m_iClip1 = 0;
|
||||
m_iBurstShotsRemaining = 0;
|
||||
m_fNextBurstShot = 0.0f;
|
||||
return;
|
||||
}
|
||||
--m_iClip1;
|
||||
|
||||
// TODO FIXME damage = 18, rangemode 0.9
|
||||
|
||||
float fInaccuracy = GetInaccuracy();
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
fInaccuracy = 0.05;
|
||||
|
||||
FX_FireBullets(
|
||||
pPlayer->entindex(),
|
||||
pPlayer->Weapon_ShootPosition(),
|
||||
pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
|
||||
GetWeaponID(),
|
||||
Secondary_Mode,
|
||||
CBaseEntity::GetPredictionRandomSeed() & 255, // wrap it for network traffic so it's the same between client and server
|
||||
fInaccuracy,
|
||||
GetSpread(),
|
||||
m_fNextBurstShot);
|
||||
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
pPlayer->m_iShotsFired++;
|
||||
|
||||
--m_iBurstShotsRemaining;
|
||||
|
||||
if ( m_iBurstShotsRemaining > 0 )
|
||||
m_fNextBurstShot += kGlockBurstCycleTime;
|
||||
else
|
||||
m_fNextBurstShot = 0.0;
|
||||
|
||||
// update accuracy
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[Secondary_Mode];
|
||||
}
|
||||
|
||||
|
||||
void CWeaponGlock::ItemPostFrame()
|
||||
{
|
||||
while ( m_iBurstShotsRemaining > 0 && gpGlobals->curtime >= m_fNextBurstShot )
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
FireRemaining(0.05f);
|
||||
else
|
||||
FireRemaining(GetSpread());
|
||||
}
|
||||
|
||||
BaseClass::ItemPostFrame();
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponGlock::Reload()
|
||||
{
|
||||
if ( m_iBurstShotsRemaining != 0 )
|
||||
return true;
|
||||
|
||||
if ( !DefaultPistolReload() )
|
||||
return false;
|
||||
|
||||
m_flAccuracy = 0.9;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWeaponGlock::WeaponIdle()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if (m_flTimeWeaponIdle > gpGlobals->curtime)
|
||||
return;
|
||||
|
||||
if ( pPlayer->HasShield() )
|
||||
{
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 20 );
|
||||
|
||||
//MIKETODO: shields
|
||||
//if ( FBitSet(m_iWeaponState, WPNSTATE_SHIELD_DRAWN) )
|
||||
// SendWeaponAnim( GLOCK18_SHIELD_IDLE, UseDecrement() ? 1:0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// only idle if the slid isn't back
|
||||
if (m_iClip1 != 0)
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_IDLE );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "gamerules.h"
|
||||
#include "npcevent.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "weapon_hegrenade.h"
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
#include "items.h"
|
||||
#include "hegrenade_projectile.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define GRENADE_TIMER 3.0f //Seconds
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( HEGrenade, DT_HEGrenade )
|
||||
|
||||
BEGIN_NETWORK_TABLE(CHEGrenade, DT_HEGrenade)
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CHEGrenade )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_hegrenade, CHEGrenade );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_hegrenade );
|
||||
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
BEGIN_DATADESC( CHEGrenade )
|
||||
END_DATADESC()
|
||||
|
||||
void CHEGrenade::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer )
|
||||
{
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [Forrest] Start a new bullet group so that damage dealt by the grenade will be counted as a separate hit from damage previously dealt.
|
||||
//=============================================================================
|
||||
#ifdef GAME_DLL
|
||||
CCSPlayer *pCSPlayer = ToCSPlayer( pPlayer );
|
||||
if ( pCSPlayer )
|
||||
{
|
||||
pCSPlayer->StartNewBulletGroup();
|
||||
}
|
||||
#endif
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
CHEGrenadeProjectile::Create( vecSrc, vecAngles, vecVel, angImpulse, pPlayer, GRENADE_TIMER );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef WEAPON_HEGRENADE_H
|
||||
#define WEAPON_HEGRENADE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "weapon_basecsgrenade.h"
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#define CHEGrenade C_HEGrenade
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Fragmentation grenades
|
||||
//-----------------------------------------------------------------------------
|
||||
class CHEGrenade : public CBaseCSGrenade
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CHEGrenade, CBaseCSGrenade );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CHEGrenade() {}
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_HEGRENADE; }
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#else
|
||||
DECLARE_DATADESC();
|
||||
|
||||
virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer );
|
||||
|
||||
#endif
|
||||
|
||||
CHEGrenade( const CHEGrenade & ) {}
|
||||
};
|
||||
|
||||
|
||||
#endif // WEAPON_HEGRENADE_H
|
||||
@@ -0,0 +1,517 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_knife.h"
|
||||
#include "cs_gamerules.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#include "c_cs_player.h"
|
||||
#else
|
||||
#include "cs_player.h"
|
||||
#include "ilagcompensationmanager.h"
|
||||
#include "cs_gamestats.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define KNIFE_BODYHIT_VOLUME 128
|
||||
#define KNIFE_WALLHIT_VOLUME 512
|
||||
|
||||
|
||||
Vector head_hull_mins( -16, -16, -18 );
|
||||
Vector head_hull_maxs( 16, 16, 18 );
|
||||
|
||||
#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_SendActiveLocalKnifeDataTable( 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 /*&& pPlayer->GetActiveWeapon() == pWeapon*/ )
|
||||
{
|
||||
pRecipients->SetOnly( pPlayer->GetClientIndex() );
|
||||
return (void*)pVarData;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendActiveLocalKnifeDataTable );
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------- //
|
||||
// CKnife tables.
|
||||
// ----------------------------------------------------------------------------- //
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( Knife, DT_WeaponKnife )
|
||||
|
||||
BEGIN_NETWORK_TABLE_NOBASE( CKnife, DT_LocalActiveWeaponKnifeData )
|
||||
#if !defined( CLIENT_DLL )
|
||||
SendPropTime( SENDINFO( m_flSmackTime ) ),
|
||||
#else
|
||||
RecvPropTime( RECVINFO( m_flSmackTime ) ),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
|
||||
BEGIN_NETWORK_TABLE( CKnife, DT_WeaponKnife )
|
||||
#if !defined( CLIENT_DLL )
|
||||
SendPropDataTable("LocalActiveWeaponKnifeData", 0, &REFERENCE_SEND_TABLE(DT_LocalActiveWeaponKnifeData), SendProxy_SendActiveLocalKnifeDataTable ),
|
||||
#else
|
||||
RecvPropDataTable("LocalActiveWeaponKnifeData", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalActiveWeaponKnifeData)),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
|
||||
#if defined CLIENT_DLL
|
||||
BEGIN_PREDICTION_DATA( CKnife )
|
||||
DEFINE_PRED_FIELD( m_flSmackTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_knife, CKnife );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_knife );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
BEGIN_DATADESC( CKnife )
|
||||
DEFINE_THINKFUNC( Smack )
|
||||
END_DATADESC()
|
||||
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------- //
|
||||
// CKnife implementation.
|
||||
// ----------------------------------------------------------------------------- //
|
||||
|
||||
CKnife::CKnife()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool CKnife::HasPrimaryAmmo()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CKnife::CanBeSelected()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CKnife::Precache()
|
||||
{
|
||||
BaseClass::Precache();
|
||||
|
||||
PrecacheScriptSound( "Weapon_Knife.Deploy" );
|
||||
PrecacheScriptSound( "Weapon_Knife.Slash" );
|
||||
PrecacheScriptSound( "Weapon_Knife.Stab" );
|
||||
PrecacheScriptSound( "Weapon_Knife.Hit" );
|
||||
}
|
||||
|
||||
void CKnife::Spawn()
|
||||
{
|
||||
Precache();
|
||||
|
||||
m_iClip1 = -1;
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
|
||||
bool CKnife::Deploy()
|
||||
{
|
||||
CPASAttenuationFilter filter( this );
|
||||
filter.UsePredictionRules();
|
||||
EmitSound( filter, entindex(), "Weapon_Knife.Deploy" );
|
||||
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
void CKnife::Holster( int skiplocal )
|
||||
{
|
||||
if ( GetPlayerOwner() )
|
||||
{
|
||||
GetPlayerOwner()->m_flNextAttack = gpGlobals->curtime + 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
void CKnife::WeaponAnimation ( int iAnimation )
|
||||
{
|
||||
/*
|
||||
int flag;
|
||||
#if defined( CLIENT_WEAPONS )
|
||||
flag = FEV_NOTHOST;
|
||||
#else
|
||||
flag = 0;
|
||||
#endif
|
||||
|
||||
PLAYBACK_EVENT_FULL( flag, pPlayer->edict(), m_usKnife,
|
||||
0.0, (float *)&g_vecZero, (float *)&g_vecZero,
|
||||
0.0,
|
||||
0.0,
|
||||
iAnimation, 2, 3, 4 );
|
||||
*/
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
distance = 1e6f;
|
||||
|
||||
vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2);
|
||||
UTIL_TraceLine( vecSrc, vecHullEnd, MASK_SOLID, pEntity, COLLISION_GROUP_NONE, &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, pEntity, COLLISION_GROUP_NONE, &tmpTrace );
|
||||
if ( tmpTrace.fraction < 1.0 )
|
||||
{
|
||||
float thisDistance = (tmpTrace.endpos - vecSrc).Length();
|
||||
if ( thisDistance < distance )
|
||||
{
|
||||
tr = tmpTrace;
|
||||
distance = thisDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CKnife::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( pPlayer )
|
||||
{
|
||||
#if !defined (CLIENT_DLL)
|
||||
// Move other players back to history positions based on local player's lag
|
||||
lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() );
|
||||
#endif
|
||||
SwingOrStab( false );
|
||||
#if !defined (CLIENT_DLL)
|
||||
lagcompensation->FinishLagCompensation( pPlayer );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void CKnife::SecondaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( pPlayer && !pPlayer->m_bIsDefusing && !CSGameRules()->IsFreezePeriod() )
|
||||
{
|
||||
#if !defined (CLIENT_DLL)
|
||||
// Move other players back to history positions based on local player's lag
|
||||
lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() );
|
||||
#endif
|
||||
SwingOrStab( true );
|
||||
#if !defined (CLIENT_DLL)
|
||||
lagcompensation->FinishLagCompensation( pPlayer );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#include "effect_dispatch_data.h"
|
||||
|
||||
void CKnife::Smack( void )
|
||||
{
|
||||
if ( !GetPlayerOwner() )
|
||||
return;
|
||||
|
||||
m_trHit.m_pEnt = m_pTraceHitEnt;
|
||||
|
||||
if ( !m_trHit.m_pEnt || (m_trHit.surface.flags & SURF_SKY) )
|
||||
return;
|
||||
|
||||
if ( m_trHit.fraction == 1.0 )
|
||||
return;
|
||||
|
||||
if ( m_trHit.m_pEnt )
|
||||
{
|
||||
CPASAttenuationFilter filter( this );
|
||||
filter.UsePredictionRules();
|
||||
|
||||
if( m_trHit.m_pEnt->IsPlayer() )
|
||||
{
|
||||
EmitSound( filter, entindex(), m_bStab?"Weapon_Knife.Stab":"Weapon_Knife.Hit" );
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitSound( filter, entindex(), "Weapon_Knife.HitWall" );
|
||||
}
|
||||
}
|
||||
|
||||
CEffectData data;
|
||||
data.m_vOrigin = m_trHit.endpos;
|
||||
data.m_vStart = m_trHit.startpos;
|
||||
data.m_nSurfaceProp = m_trHit.surface.surfaceProps;
|
||||
data.m_nDamageType = DMG_SLASH;
|
||||
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 filter( data.m_vOrigin );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
filter.RemoveRecipient( GetPlayerOwner() );
|
||||
#endif
|
||||
|
||||
data.m_vAngles = GetPlayerOwner()->GetAbsAngles();
|
||||
data.m_fFlags = 0x1; //IMPACT_NODECAL;
|
||||
te->DispatchEffect( filter, 0.0, data.m_vOrigin, "KnifeSlash", data );
|
||||
}
|
||||
|
||||
void CKnife::WeaponIdle()
|
||||
{
|
||||
if (m_flTimeWeaponIdle > gpGlobals->curtime)
|
||||
return;
|
||||
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( pPlayer->IsShieldDrawn() )
|
||||
return;
|
||||
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 20 );
|
||||
|
||||
// only idle if the slid isn't back
|
||||
SendWeaponAnim( ACT_VM_IDLE );
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [tj] Hacky cheat code to control knife damage
|
||||
//=============================================================================
|
||||
#ifndef CLIENT_DLL
|
||||
ConVar KnifeDamageScale("knife_damage_scale", "100", FCVAR_DEVELOPMENTONLY);
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
|
||||
bool CKnife::SwingOrStab( bool bStab )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return false;
|
||||
|
||||
float fRange = bStab ? 32 : 48; // knife range
|
||||
|
||||
Vector vForward; AngleVectors( pPlayer->EyeAngles(), &vForward );
|
||||
Vector vecSrc = pPlayer->Weapon_ShootPosition();
|
||||
Vector vecEnd = vecSrc + vForward * fRange;
|
||||
|
||||
trace_t tr;
|
||||
UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &tr );
|
||||
|
||||
//check for hitting glass - TODO - fix this hackiness, doesn't always line up with what FindHullIntersection returns
|
||||
#ifndef CLIENT_DLL
|
||||
CTakeDamageInfo glassDamage( pPlayer, pPlayer, 42.0f, DMG_BULLET | DMG_NEVERGIB );
|
||||
TraceAttackToTriggers( glassDamage, tr.startpos, tr.endpos, vForward );
|
||||
#endif
|
||||
|
||||
if ( tr.fraction >= 1.0 )
|
||||
{
|
||||
UTIL_TraceHull( vecSrc, vecEnd, head_hull_mins, head_hull_maxs, MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &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)
|
||||
}
|
||||
}
|
||||
|
||||
bool bDidHit = tr.fraction < 1.0f;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
bool bFirstSwing = (m_flNextPrimaryAttack + 0.4) < gpGlobals->curtime;
|
||||
#endif
|
||||
|
||||
float fPrimDelay, fSecDelay;
|
||||
|
||||
if ( bStab )
|
||||
{
|
||||
SendWeaponAnim( bDidHit ? ACT_VM_HITCENTER : ACT_VM_MISSCENTER );
|
||||
|
||||
fPrimDelay = fSecDelay = bDidHit ? 1.1f : 1.0f;
|
||||
|
||||
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_PRIMARY );
|
||||
}
|
||||
else // swing
|
||||
{
|
||||
SendWeaponAnim( bDidHit ? ACT_VM_HITCENTER : ACT_VM_MISSCENTER );
|
||||
|
||||
fPrimDelay = bDidHit ? 0.5f : 0.4f;
|
||||
fSecDelay = bDidHit ? 0.5f : 0.5f;
|
||||
|
||||
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_SECONDARY );
|
||||
}
|
||||
|
||||
if ( pPlayer->HasShield() )
|
||||
{
|
||||
fPrimDelay += 0.7f; // 0.7 seconds slower if we carry a shield
|
||||
fSecDelay += 0.7f;
|
||||
}
|
||||
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + fPrimDelay;
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + fSecDelay;
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 2 );
|
||||
|
||||
if ( !bDidHit )
|
||||
{
|
||||
// play wiff or swish sound
|
||||
CPASAttenuationFilter filter( this );
|
||||
filter.UsePredictionRules();
|
||||
EmitSound( filter, entindex(), "Weapon_Knife.Slash" );
|
||||
}
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
float flDamage = 0.0f;
|
||||
if ( bDidHit )
|
||||
{
|
||||
// play thwack, smack, or dong sound
|
||||
|
||||
CBaseEntity *pEntity = tr.m_pEnt;
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
ClearMultiDamage();
|
||||
|
||||
flDamage = 42.0f;
|
||||
|
||||
if ( bStab )
|
||||
{
|
||||
flDamage = 65.0f;
|
||||
|
||||
if ( pEntity && pEntity->IsPlayer() )
|
||||
{
|
||||
Vector vTragetForward;
|
||||
|
||||
AngleVectors( pEntity->GetAbsAngles(), &vTragetForward );
|
||||
|
||||
Vector2D vecLOS = (pEntity->GetAbsOrigin() - pPlayer->GetAbsOrigin()).AsVector2D();
|
||||
Vector2DNormalize( vecLOS );
|
||||
|
||||
float flDot = vecLOS.Dot( vTragetForward.AsVector2D() );
|
||||
|
||||
//Triple the damage if we are stabbing them in the back.
|
||||
if ( flDot > 0.80f )
|
||||
flDamage *= 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( bFirstSwing )
|
||||
{
|
||||
// first swing does full damage
|
||||
flDamage = 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
// subsequent swings do less
|
||||
flDamage = 15;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [tj] Hacky cheat to lower knife damage for testing
|
||||
//=============================================================================
|
||||
|
||||
flDamage *= (KnifeDamageScale.GetInt() / 100.0f);
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
|
||||
CTakeDamageInfo info( pPlayer, pPlayer, flDamage, DMG_BULLET | DMG_NEVERGIB );
|
||||
|
||||
CalculateMeleeDamageForce( &info, vForward, tr.endpos, 1.0f/flDamage );
|
||||
pEntity->DispatchTraceAttack( info, vForward, &tr );
|
||||
ApplyMultiDamage();
|
||||
}
|
||||
|
||||
CCS_GameStats.Event_KnifeUse( pPlayer, bStab, flDamage );
|
||||
|
||||
#endif
|
||||
|
||||
if ( bDidHit )
|
||||
{
|
||||
// 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_bStab = bStab; //store this so we know what hit sound to play
|
||||
|
||||
m_flSmackTime = gpGlobals->curtime + (bStab?0.2f:0.1f);
|
||||
}
|
||||
|
||||
return bDidHit;
|
||||
}
|
||||
|
||||
void CKnife::ItemPostFrame( void )
|
||||
{
|
||||
if( m_flSmackTime > 0 && gpGlobals->curtime > m_flSmackTime )
|
||||
{
|
||||
Smack();
|
||||
m_flSmackTime = -1;
|
||||
}
|
||||
|
||||
BaseClass::ItemPostFrame();
|
||||
}
|
||||
|
||||
bool CKnife::CanDrop()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef WEAPON_KNIFE_H
|
||||
#define WEAPON_KNIFE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "weapon_csbase.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CKnife C_Knife
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- //
|
||||
// CKnife class definition.
|
||||
// ----------------------------------------------------------------------------- //
|
||||
|
||||
class CKnife : public CWeaponCSBase
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CKnife, CWeaponCSBase );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_DATADESC();
|
||||
#endif
|
||||
|
||||
|
||||
CKnife();
|
||||
|
||||
// We say yes to this so the weapon system lets us switch to it.
|
||||
virtual bool HasPrimaryAmmo();
|
||||
virtual bool CanBeSelected();
|
||||
|
||||
virtual void Precache();
|
||||
|
||||
void Spawn();
|
||||
void Smack();
|
||||
//void Smack( trace_t *pTr, float delay );
|
||||
bool SwingOrStab( bool bStab );
|
||||
void PrimaryAttack();
|
||||
void SecondaryAttack();
|
||||
void WeaponAnimation( int iAnimation );
|
||||
|
||||
virtual void ItemPostFrame( void );
|
||||
|
||||
// virtual float GetSpread() const;
|
||||
|
||||
bool Deploy();
|
||||
void Holster( int skiplocal = 0 );
|
||||
bool CanDrop();
|
||||
|
||||
void WeaponIdle();
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_KNIFE; }
|
||||
|
||||
public:
|
||||
|
||||
trace_t m_trHit;
|
||||
EHANDLE m_pTraceHitEnt;
|
||||
|
||||
CNetworkVar( float, m_flSmackTime );
|
||||
bool m_bStab;
|
||||
|
||||
private:
|
||||
CKnife( const CKnife & ) {}
|
||||
};
|
||||
|
||||
|
||||
#endif // WEAPON_KNIFE_H
|
||||
@@ -0,0 +1,105 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponM249 C_WeaponM249
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponM249 : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponM249, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponM249();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_M249; }
|
||||
|
||||
|
||||
private:
|
||||
CWeaponM249( const CWeaponM249 & );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponM249, DT_WeaponM249 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponM249, DT_WeaponM249 )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponM249 )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_m249, CWeaponM249 );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_m249 );
|
||||
|
||||
|
||||
|
||||
CWeaponM249::CWeaponM249()
|
||||
{
|
||||
}
|
||||
|
||||
float CWeaponM249::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 0.045f + 0.5f * m_flAccuracy;
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 140)
|
||||
return 0.045f + 0.095f * m_flAccuracy;
|
||||
else
|
||||
return 0.03f * m_flAccuracy;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CWeaponM249::PrimaryAttack( void )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( !CSBaseGunFire( GetCSWpnData().m_flCycleTime, Primary_Mode ) )
|
||||
return;
|
||||
|
||||
pPlayer = GetPlayerOwner();
|
||||
|
||||
// CSBaseGunFire can kill us, forcing us to drop our weapon, if we shoot something that explodes
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
pPlayer->KickBack (1.8, 0.65, 0.45, 0.125, 5, 3.5, 8);
|
||||
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
pPlayer->KickBack (1.1, 0.5, 0.3, 0.06, 4, 3, 8);
|
||||
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
pPlayer->KickBack (0.75, 0.325, 0.25, 0.025, 3.5, 2.5, 9);
|
||||
|
||||
else
|
||||
pPlayer->KickBack (0.8, 0.35, 0.3, 0.03, 3.75, 3, 9);
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "fx_cs_shared.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponM3 C_WeaponM3
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
#include "te_shotgun_shot.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponM3 : public CWeaponCSBase
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponM3, CWeaponCSBase );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponM3();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
virtual bool Reload();
|
||||
virtual void WeaponIdle();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
virtual float GetSpread() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_M3; }
|
||||
|
||||
private:
|
||||
|
||||
CWeaponM3( const CWeaponM3 & );
|
||||
|
||||
float m_flPumpTime;
|
||||
CNetworkVar( int, m_reloadState );
|
||||
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponM3, DT_WeaponM3 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponM3, DT_WeaponM3 )
|
||||
#ifdef CLIENT_DLL
|
||||
RecvPropInt( RECVINFO( m_reloadState ) )
|
||||
#else
|
||||
SendPropInt( SENDINFO( m_reloadState ), 2, SPROP_UNSIGNED )
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#if defined(CLIENT_DLL)
|
||||
BEGIN_PREDICTION_DATA( CWeaponM3 )
|
||||
DEFINE_PRED_FIELD( m_reloadState, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_m3, CWeaponM3 );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_m3 );
|
||||
|
||||
|
||||
|
||||
CWeaponM3::CWeaponM3()
|
||||
{
|
||||
m_flPumpTime = 0;
|
||||
m_reloadState = 0;
|
||||
}
|
||||
|
||||
float CWeaponM3::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
float CWeaponM3::GetSpread() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
return 0.0675f;
|
||||
|
||||
return GetCSWpnData().m_fSpread[Primary_Mode];
|
||||
}
|
||||
|
||||
void CWeaponM3::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
float flCycleTime = GetCSWpnData().m_flCycleTime;
|
||||
|
||||
// don't fire underwater
|
||||
if (pPlayer->GetWaterLevel() == 3)
|
||||
{
|
||||
PlayEmptySound( );
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.15;
|
||||
return;
|
||||
}
|
||||
|
||||
// Out of ammo?
|
||||
if ( m_iClip1 <= 0 )
|
||||
{
|
||||
Reload();
|
||||
if ( m_iClip1 == 0 )
|
||||
{
|
||||
PlayEmptySound();
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
||||
|
||||
m_iClip1--;
|
||||
pPlayer->DoMuzzleFlash();
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
// Dispatch the FX right away with full accuracy.
|
||||
float flCurAttack = CalculateNextAttackTime( flCycleTime );
|
||||
FX_FireBullets(
|
||||
pPlayer->entindex(),
|
||||
pPlayer->Weapon_ShootPosition(),
|
||||
pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
|
||||
GetWeaponID(),
|
||||
Primary_Mode,
|
||||
CBaseEntity::GetPredictionRandomSeed() & 255, // wrap it for network traffic so it's the same between client and server
|
||||
GetInaccuracy(),
|
||||
GetSpread(),
|
||||
flCurAttack );
|
||||
|
||||
if (!m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0)
|
||||
{
|
||||
// HEV suit - indicate out of ammo condition
|
||||
pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0);
|
||||
}
|
||||
|
||||
if (m_iClip1 != 0)
|
||||
m_flPumpTime = gpGlobals->curtime + 0.5;
|
||||
|
||||
if (m_iClip1 != 0)
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 2.5 );
|
||||
else
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 0.875 );
|
||||
m_reloadState = 0;
|
||||
|
||||
// update accuracy
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[Primary_Mode];
|
||||
|
||||
// Update punch angles.
|
||||
QAngle angle = pPlayer->GetPunchAngle();
|
||||
|
||||
if ( pPlayer->GetFlags() & FL_ONGROUND )
|
||||
{
|
||||
angle.x -= SharedRandomInt( "M3PunchAngleGround", 4, 6 );
|
||||
}
|
||||
else
|
||||
{
|
||||
angle.x -= SharedRandomInt( "M3PunchAngleAir", 8, 11 );
|
||||
}
|
||||
|
||||
pPlayer->SetPunchAngle( angle );
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponM3::Reload()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return false;
|
||||
|
||||
if (pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 || m_iClip1 == GetMaxClip1())
|
||||
return true;
|
||||
|
||||
// don't reload until recoil is done
|
||||
if (m_flNextPrimaryAttack > gpGlobals->curtime)
|
||||
return true;
|
||||
|
||||
// check to see if we're ready to reload
|
||||
if (m_reloadState == 0)
|
||||
{
|
||||
pPlayer->SetAnimation( PLAYER_RELOAD );
|
||||
|
||||
SendWeaponAnim( ACT_SHOTGUN_RELOAD_START );
|
||||
m_reloadState = 1;
|
||||
pPlayer->m_flNextAttack = gpGlobals->curtime + 0.5;
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.5;
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 0.5;
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 0.5 );
|
||||
|
||||
#ifdef GAME_DLL
|
||||
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD_START );
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (m_reloadState == 1)
|
||||
{
|
||||
if (m_flTimeWeaponIdle > gpGlobals->curtime)
|
||||
return true;
|
||||
// was waiting for gun to move to side
|
||||
m_reloadState = 2;
|
||||
|
||||
SendWeaponAnim( ACT_VM_RELOAD );
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 0.5 );
|
||||
#ifdef GAME_DLL
|
||||
if ( m_iClip1 == 7 )
|
||||
{
|
||||
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD_END );
|
||||
}
|
||||
else
|
||||
{
|
||||
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD_LOOP );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add them to the clip
|
||||
m_iClip1 += 1;
|
||||
|
||||
#ifdef GAME_DLL
|
||||
SendReloadEvents();
|
||||
#endif
|
||||
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
|
||||
if ( pPlayer )
|
||||
pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType );
|
||||
|
||||
m_reloadState = 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CWeaponM3::WeaponIdle()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if (m_flPumpTime && m_flPumpTime < gpGlobals->curtime)
|
||||
{
|
||||
// play pumping sound
|
||||
m_flPumpTime = 0;
|
||||
}
|
||||
|
||||
if (m_flTimeWeaponIdle < gpGlobals->curtime)
|
||||
{
|
||||
if (m_iClip1 == 0 && m_reloadState == 0 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ))
|
||||
{
|
||||
Reload( );
|
||||
}
|
||||
else if (m_reloadState != 0)
|
||||
{
|
||||
if (m_iClip1 != 8 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ))
|
||||
{
|
||||
Reload( );
|
||||
}
|
||||
else
|
||||
{
|
||||
// reload debounce has timed out
|
||||
//MIKETODO: shotgun anims
|
||||
SendWeaponAnim( ACT_SHOTGUN_RELOAD_FINISH );
|
||||
|
||||
// play cocking sound
|
||||
m_reloadState = 0;
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 1.5 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_IDLE );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponM4A1 C_WeaponM4A1
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponM4A1 : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponM4A1, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponM4A1();
|
||||
|
||||
virtual void Spawn();
|
||||
virtual void Precache();
|
||||
|
||||
virtual void SecondaryAttack();
|
||||
virtual void PrimaryAttack();
|
||||
virtual bool Deploy();
|
||||
virtual bool Reload();
|
||||
virtual void WeaponIdle();
|
||||
virtual bool Holster( CBaseCombatWeapon *pSwitchingTo );
|
||||
virtual void Drop( const Vector &vecVelocity );
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_M4A1; }
|
||||
|
||||
// return true if this weapon has a silencer equipped
|
||||
virtual bool IsSilenced( void ) const { return m_bSilencerOn; }
|
||||
|
||||
virtual Activity GetDeployActivity( void );
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
virtual int GetMuzzleFlashStyle( void );
|
||||
#endif
|
||||
|
||||
virtual const char *GetWorldModel( void ) const;
|
||||
virtual int GetWorldModelIndex( void );
|
||||
|
||||
private:
|
||||
|
||||
CWeaponM4A1( const CWeaponM4A1 & );
|
||||
|
||||
void DoFireEffects();
|
||||
|
||||
CNetworkVar( bool, m_bSilencerOn );
|
||||
CNetworkVar( float, m_flDoneSwitchingSilencer ); // soonest time switching the silencer will be complete
|
||||
|
||||
int m_silencedModelIndex;
|
||||
bool m_inPrecache;
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponM4A1, DT_WeaponM4A1 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponM4A1, DT_WeaponM4A1 )
|
||||
#ifdef CLIENT_DLL
|
||||
RecvPropBool( RECVINFO( m_bSilencerOn ) ),
|
||||
RecvPropTime( RECVINFO( m_flDoneSwitchingSilencer ) ),
|
||||
#else
|
||||
SendPropBool( SENDINFO( m_bSilencerOn ) ),
|
||||
SendPropTime( SENDINFO( m_flDoneSwitchingSilencer ) ),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponM4A1 )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_m4a1, CWeaponM4A1 );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_m4a1 );
|
||||
|
||||
|
||||
|
||||
CWeaponM4A1::CWeaponM4A1()
|
||||
{
|
||||
m_bSilencerOn = false;
|
||||
m_flDoneSwitchingSilencer = 0.0f;
|
||||
m_inPrecache = false;
|
||||
}
|
||||
|
||||
|
||||
void CWeaponM4A1::Spawn( )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
|
||||
m_bSilencerOn = false;
|
||||
m_weaponMode = Primary_Mode;
|
||||
m_flDoneSwitchingSilencer = 0.0f;
|
||||
m_bDelayFire = true;
|
||||
}
|
||||
|
||||
|
||||
void CWeaponM4A1::Precache()
|
||||
{
|
||||
m_inPrecache = true;
|
||||
BaseClass::Precache();
|
||||
|
||||
m_silencedModelIndex = CBaseEntity::PrecacheModel( GetCSWpnData().m_szSilencerModel );
|
||||
m_inPrecache = false;
|
||||
}
|
||||
|
||||
|
||||
int CWeaponM4A1::GetWorldModelIndex( void )
|
||||
{
|
||||
if ( !m_bSilencerOn || m_inPrecache )
|
||||
{
|
||||
return m_iWorldModelIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_silencedModelIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char * CWeaponM4A1::GetWorldModel( void ) const
|
||||
{
|
||||
if ( !m_bSilencerOn || m_inPrecache )
|
||||
{
|
||||
return BaseClass::GetWorldModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetCSWpnData().m_szSilencerModel;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponM4A1::Deploy()
|
||||
{
|
||||
bool ret = BaseClass::Deploy();
|
||||
|
||||
m_flDoneSwitchingSilencer = 0.0f;
|
||||
m_bDelayFire = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Activity CWeaponM4A1::GetDeployActivity( void )
|
||||
{
|
||||
if( IsSilenced() )
|
||||
{
|
||||
return ACT_VM_DRAW_SILENCED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ACT_VM_DRAW;
|
||||
}
|
||||
}
|
||||
|
||||
bool CWeaponM4A1::Holster( CBaseCombatWeapon *pSwitchingTo )
|
||||
{
|
||||
if ( gpGlobals->curtime < m_flDoneSwitchingSilencer )
|
||||
{
|
||||
// still switching the silencer. Cancel the switch.
|
||||
m_bSilencerOn = !m_bSilencerOn;
|
||||
m_weaponMode = m_bSilencerOn ? Secondary_Mode : Primary_Mode;
|
||||
SetWeaponModelIndex( GetWorldModel() );
|
||||
}
|
||||
|
||||
return BaseClass::Holster( pSwitchingTo );
|
||||
}
|
||||
|
||||
void CWeaponM4A1::Drop( const Vector &vecVelocity )
|
||||
{
|
||||
if ( gpGlobals->curtime < m_flDoneSwitchingSilencer )
|
||||
{
|
||||
// still switching the silencer. Cancel the switch.
|
||||
m_bSilencerOn = !m_bSilencerOn;
|
||||
m_weaponMode = m_bSilencerOn ? Secondary_Mode : Primary_Mode;
|
||||
SetWeaponModelIndex( GetWorldModel() );
|
||||
}
|
||||
|
||||
BaseClass::Drop( vecVelocity );
|
||||
}
|
||||
|
||||
void CWeaponM4A1::SecondaryAttack()
|
||||
{
|
||||
if ( m_bSilencerOn )
|
||||
{
|
||||
m_bSilencerOn = false;
|
||||
m_weaponMode = Primary_Mode;
|
||||
SendWeaponAnim( ACT_VM_DETACH_SILENCER );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bSilencerOn = true;
|
||||
m_weaponMode = Secondary_Mode;
|
||||
SendWeaponAnim( ACT_VM_ATTACH_SILENCER );
|
||||
}
|
||||
m_flDoneSwitchingSilencer = gpGlobals->curtime + 2;
|
||||
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 2;
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 2;
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 2 );
|
||||
|
||||
SetWeaponModelIndex( GetWorldModel() );
|
||||
}
|
||||
|
||||
float CWeaponM4A1::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
{
|
||||
return 0.035f + 0.4f * m_flAccuracy;
|
||||
}
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 140)
|
||||
{
|
||||
return 0.035f + 0.07f * m_flAccuracy;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_bSilencerOn )
|
||||
return 0.025f * m_flAccuracy;
|
||||
else
|
||||
return 0.02f * m_flAccuracy;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CWeaponM4A1::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( !CSBaseGunFire( GetCSWpnData().m_flCycleTime, m_weaponMode ) )
|
||||
return;
|
||||
|
||||
if ( m_bSilencerOn )
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK_SILENCED );
|
||||
|
||||
pPlayer = GetPlayerOwner();
|
||||
|
||||
// CSBaseGunFire can kill us, forcing us to drop our weapon, if we shoot something that explodes
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
pPlayer->KickBack (1.0, 0.45, 0.28, 0.045, 3.75, 3, 7);
|
||||
else if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
pPlayer->KickBack (1.2, 0.5, 0.23, 0.15, 5.5, 3.5, 6);
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
pPlayer->KickBack (0.6, 0.3, 0.2, 0.0125, 3.25, 2, 7);
|
||||
else
|
||||
pPlayer->KickBack (0.65, 0.35, 0.25, 0.015, 3.5, 2.25, 7);
|
||||
}
|
||||
|
||||
|
||||
void CWeaponM4A1::DoFireEffects()
|
||||
{
|
||||
if ( !m_bSilencerOn )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( pPlayer )
|
||||
{
|
||||
pPlayer->DoMuzzleFlash();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CWeaponM4A1::Reload()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return false;
|
||||
|
||||
if (pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0)
|
||||
return false;
|
||||
|
||||
int iResult = 0;
|
||||
|
||||
if ( m_bSilencerOn )
|
||||
iResult = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD_SILENCED );
|
||||
else
|
||||
iResult = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
|
||||
|
||||
if ( !iResult )
|
||||
return false;
|
||||
|
||||
pPlayer->SetAnimation( PLAYER_RELOAD );
|
||||
|
||||
if ((iResult) && (pPlayer->GetFOV() != pPlayer->GetDefaultFOV()))
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV() );
|
||||
}
|
||||
|
||||
m_flAccuracy = 0.2;
|
||||
pPlayer->m_iShotsFired = 0;
|
||||
m_bDelayFire = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CWeaponM4A1::WeaponIdle()
|
||||
{
|
||||
if (m_flTimeWeaponIdle > gpGlobals->curtime)
|
||||
return;
|
||||
|
||||
// only idle if the slid isn't back
|
||||
if ( m_iClip1 != 0 )
|
||||
{
|
||||
SetWeaponIdleTime( gpGlobals->curtime + GetCSWpnData().m_flIdleInterval );
|
||||
if ( m_bSilencerOn )
|
||||
SendWeaponAnim( ACT_VM_IDLE_SILENCED );
|
||||
else
|
||||
SendWeaponAnim( ACT_VM_IDLE );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
int CWeaponM4A1::GetMuzzleFlashStyle( void )
|
||||
{
|
||||
if( m_bSilencerOn )
|
||||
{
|
||||
return CS_MUZZLEFLASH_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CS_MUZZLEFLASH_X;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,130 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponMAC10 C_WeaponMAC10
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponMAC10 : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponMAC10, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponMAC10();
|
||||
|
||||
virtual void Spawn();
|
||||
virtual void PrimaryAttack();
|
||||
virtual bool Deploy();
|
||||
virtual bool Reload();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_MAC10; }
|
||||
|
||||
|
||||
private:
|
||||
CWeaponMAC10( const CWeaponMAC10 & );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponMAC10, DT_WeaponMAC10 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponMAC10, DT_WeaponMAC10 )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponMAC10 )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_mac10, CWeaponMAC10 );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_mac10 );
|
||||
|
||||
|
||||
|
||||
CWeaponMAC10::CWeaponMAC10()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CWeaponMAC10::Spawn( )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
|
||||
m_flAccuracy = 0.15;
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponMAC10::Deploy()
|
||||
{
|
||||
bool ret = BaseClass::Deploy();
|
||||
|
||||
m_flAccuracy = 0.15;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CWeaponMAC10::Reload()
|
||||
{
|
||||
bool ret = BaseClass::Reload();
|
||||
|
||||
m_flAccuracy = 0.15;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
float CWeaponMAC10::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 0.375f * m_flAccuracy;
|
||||
else
|
||||
return 0.03f * m_flAccuracy;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CWeaponMAC10::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( !CSBaseGunFire( GetCSWpnData().m_flCycleTime, Primary_Mode ) )
|
||||
return;
|
||||
|
||||
// CSBaseGunFire can kill us, forcing us to drop our weapon, if we shoot something that explodes
|
||||
pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) ) // jumping
|
||||
pPlayer->KickBack (1.3, 0.55, 0.4, 0.05, 4.75, 3.75, 5);
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5) // running
|
||||
pPlayer->KickBack (0.9, 0.45, 0.25, 0.035, 3.5, 2.75, 7);
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) ) // ducking
|
||||
pPlayer->KickBack (0.75, 0.4, 0.175, 0.03, 2.75, 2.5, 10);
|
||||
else // standing
|
||||
pPlayer->KickBack (0.775, 0.425, 0.2, 0.03, 3, 2.75, 9);
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponMP5Navy C_WeaponMP5Navy
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponMP5Navy : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponMP5Navy, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponMP5Navy();
|
||||
|
||||
virtual void Spawn();
|
||||
virtual void PrimaryAttack();
|
||||
virtual bool Deploy();
|
||||
virtual bool Reload();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_MP5NAVY; }
|
||||
|
||||
|
||||
private:
|
||||
CWeaponMP5Navy( const CWeaponMP5Navy & );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponMP5Navy, DT_WeaponMP5Navy )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponMP5Navy, DT_WeaponMP5Navy )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponMP5Navy )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_mp5navy, CWeaponMP5Navy );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_mp5navy );
|
||||
|
||||
|
||||
|
||||
CWeaponMP5Navy::CWeaponMP5Navy()
|
||||
{
|
||||
}
|
||||
|
||||
void CWeaponMP5Navy::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
|
||||
m_flAccuracy = 0.0;
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponMP5Navy::Deploy( )
|
||||
{
|
||||
bool ret = BaseClass::Deploy();
|
||||
|
||||
m_flAccuracy = 0.0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CWeaponMP5Navy::Reload( )
|
||||
{
|
||||
bool ret = BaseClass::Reload();
|
||||
|
||||
m_flAccuracy = 0.0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
float CWeaponMP5Navy::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 0.2f * m_flAccuracy;
|
||||
else
|
||||
return 0.04f * m_flAccuracy;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CWeaponMP5Navy::PrimaryAttack( void )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( !CSBaseGunFire( GetCSWpnData().m_flCycleTime, Primary_Mode ) )
|
||||
return;
|
||||
|
||||
// CSBaseGunFire can kill us, forcing us to drop our weapon, if we shoot something that explodes
|
||||
pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
// Kick the gun based on the state of the player.
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
pPlayer->KickBack (0.9, 0.475, 0.35, 0.0425, 5, 3, 6);
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
pPlayer->KickBack (0.5, 0.275, 0.2, 0.03, 3, 2, 10);
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
pPlayer->KickBack (0.225, 0.15, 0.1, 0.015, 2, 1, 10);
|
||||
else
|
||||
pPlayer->KickBack (0.25, 0.175, 0.125, 0.02, 2.25, 1.25, 10);
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "fx_cs_shared.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponP228 C_WeaponP228
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponP228 : public CWeaponCSBase
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponP228, CWeaponCSBase );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponP228();
|
||||
|
||||
virtual void Spawn();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
virtual bool Deploy();
|
||||
|
||||
virtual bool Reload();
|
||||
virtual void WeaponIdle();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_P228; }
|
||||
|
||||
private:
|
||||
|
||||
CWeaponP228( const CWeaponP228 & );
|
||||
|
||||
float m_flLastFire;
|
||||
};
|
||||
|
||||
#if defined CLIENT_DLL
|
||||
BEGIN_PREDICTION_DATA( CWeaponP228 )
|
||||
DEFINE_FIELD( m_flLastFire, FIELD_FLOAT ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_p228, CWeaponP228 );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_p228 );
|
||||
|
||||
|
||||
|
||||
CWeaponP228::CWeaponP228()
|
||||
{
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
|
||||
void CWeaponP228::Spawn( )
|
||||
{
|
||||
m_flAccuracy = 0.9;
|
||||
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponP228::Deploy( )
|
||||
{
|
||||
m_flAccuracy = 0.9;
|
||||
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponP228, DT_WeaponP228 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponP228, DT_WeaponP228 )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
|
||||
float CWeaponP228::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 1.5f * (1 - m_flAccuracy);
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
return 0.255f * (1 - m_flAccuracy);
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
return 0.075f * (1 - m_flAccuracy);
|
||||
else
|
||||
return 0.15f * (1 - m_flAccuracy);
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
|
||||
void CWeaponP228::PrimaryAttack( void )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
// Mark the time of this shot and determine the accuracy modifier based on the last shot fired...
|
||||
m_flAccuracy -= (0.3)*(0.325 - (gpGlobals->curtime - m_flLastFire));
|
||||
|
||||
if (m_flAccuracy > 0.9)
|
||||
m_flAccuracy = 0.9;
|
||||
else if (m_flAccuracy < 0.6)
|
||||
m_flAccuracy = 0.6;
|
||||
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
|
||||
if (m_iClip1 <= 0)
|
||||
{
|
||||
if ( m_bFireOnEmpty )
|
||||
{
|
||||
PlayEmptySound();
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.1f;
|
||||
m_bFireOnEmpty = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pPlayer->m_iShotsFired++;
|
||||
|
||||
m_iClip1--;
|
||||
|
||||
pPlayer->DoMuzzleFlash();
|
||||
//SetPlayerShieldAnim();
|
||||
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
// Aiming
|
||||
FX_FireBullets(
|
||||
pPlayer->entindex(),
|
||||
pPlayer->Weapon_ShootPosition(),
|
||||
pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
|
||||
GetWeaponID(),
|
||||
Primary_Mode,
|
||||
CBaseEntity::GetPredictionRandomSeed() & 255,
|
||||
GetInaccuracy(),
|
||||
GetSpread());
|
||||
|
||||
m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + GetCSWpnData().m_flCycleTime;
|
||||
|
||||
if (!m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0)
|
||||
{
|
||||
// HEV suit - indicate out of ammo condition
|
||||
pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0);
|
||||
}
|
||||
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 2 );
|
||||
|
||||
//ResetPlayerShieldAnim();
|
||||
|
||||
// update accuracy
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[Primary_Mode];
|
||||
|
||||
QAngle angle = pPlayer->GetPunchAngle();
|
||||
angle.x -= 2;
|
||||
pPlayer->SetPunchAngle( angle );
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponP228::Reload()
|
||||
{
|
||||
if ( !DefaultPistolReload() )
|
||||
return false;
|
||||
|
||||
m_flAccuracy = 0.9;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWeaponP228::WeaponIdle()
|
||||
{
|
||||
if (m_flTimeWeaponIdle > gpGlobals->curtime)
|
||||
return;
|
||||
|
||||
// only idle if the slid isn't back
|
||||
if (m_iClip1 != 0)
|
||||
{
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 3.0 ) ;
|
||||
SendWeaponAnim( ACT_VM_IDLE );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponP90 C_WeaponP90
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponP90 : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponP90, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponP90();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_P90; }
|
||||
|
||||
|
||||
private:
|
||||
CWeaponP90( const CWeaponP90 & );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponP90, DT_WeaponP90 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponP90, DT_WeaponP90 )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponP90 )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_p90, CWeaponP90 );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_p90 );
|
||||
|
||||
|
||||
|
||||
CWeaponP90::CWeaponP90()
|
||||
{
|
||||
}
|
||||
|
||||
float CWeaponP90::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 0.3f * m_flAccuracy;
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 170)
|
||||
return 0.115f * m_flAccuracy;
|
||||
else
|
||||
return 0.045f * m_flAccuracy;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CWeaponP90::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( !CSBaseGunFire( GetCSWpnData().m_flCycleTime, Primary_Mode ) )
|
||||
return;
|
||||
|
||||
// Kick the gun based on the state of the player.
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
pPlayer->KickBack (0.9, 0.45, 0.35, 0.04, 5.25, 3.5, 4);
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
pPlayer->KickBack (0.45, 0.3, 0.2, 0.0275, 4, 2.25, 7);
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
pPlayer->KickBack (0.275, 0.2, 0.125, 0.02, 3, 1, 9);
|
||||
else
|
||||
pPlayer->KickBack (0.3, 0.225, 0.125, 0.02, 3.25, 1.25, 8);
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponScout C_WeaponScout
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
#include "KeyValues.h"
|
||||
|
||||
#endif
|
||||
|
||||
const int cScoutMidZoomFOV = 40;
|
||||
const int cScoutMaxZoomFOV = 15;
|
||||
|
||||
|
||||
class CWeaponScout : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponScout, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponScout();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
virtual void SecondaryAttack();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
virtual float GetMaxSpeed() const;
|
||||
virtual bool Reload();
|
||||
virtual bool Deploy();
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_SCOUT; }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
CWeaponScout( const CWeaponScout & );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponScout, DT_WeaponScout )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponScout, DT_WeaponScout )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponScout )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_scout, CWeaponScout );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_scout );
|
||||
|
||||
|
||||
|
||||
CWeaponScout::CWeaponScout()
|
||||
{
|
||||
}
|
||||
|
||||
void CWeaponScout::SecondaryAttack()
|
||||
{
|
||||
const float kZoomTime = 0.10f;
|
||||
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if (pPlayer == NULL)
|
||||
{
|
||||
Assert(pPlayer != NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pPlayer->GetFOV() == pPlayer->GetDefaultFOV())
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, cScoutMidZoomFOV, kZoomTime );
|
||||
m_weaponMode = Secondary_Mode;
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyAltSwitch;
|
||||
}
|
||||
else if (pPlayer->GetFOV() == cScoutMidZoomFOV)
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, cScoutMaxZoomFOV, kZoomTime );
|
||||
m_weaponMode = Secondary_Mode;
|
||||
}
|
||||
else if (pPlayer->GetFOV() == cScoutMaxZoomFOV)
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV(), kZoomTime );
|
||||
m_weaponMode = Primary_Mode;
|
||||
}
|
||||
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 0.3f;
|
||||
m_zoomFullyActiveTime = gpGlobals->curtime + 0.15; // The worst zoom time from above.
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// If this isn't guarded, the sound will be emitted twice, once by the server and once by the client.
|
||||
// Let the server play it since if only the client plays it, it's liable to get played twice cause of
|
||||
// a prediction error. joy.
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [tj] Playing this from the player so that we don't try to play the sound outside the level.
|
||||
//=============================================================================
|
||||
if ( GetPlayerOwner() )
|
||||
{
|
||||
GetPlayerOwner()->EmitSound( "Default.Zoom" ); // zoom sound
|
||||
}
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
// let the bots hear the rifle zoom
|
||||
IGameEvent * event = gameeventmanager->CreateEvent( "weapon_zoom" );
|
||||
if( event )
|
||||
{
|
||||
event->SetInt( "userid", pPlayer->GetUserID() );
|
||||
gameeventmanager->FireEvent( event );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
float CWeaponScout::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if (pPlayer == NULL)
|
||||
return 0.0f;
|
||||
|
||||
float fSpread = 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
fSpread = 0.2f;
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 170)
|
||||
fSpread = 0.075f;
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
fSpread = 0.0f;
|
||||
else
|
||||
fSpread = 0.007f;
|
||||
|
||||
// If we are not zoomed in, or we have very recently zoomed and are still transitioning, the bullet diverts more.
|
||||
if (pPlayer->GetFOV() == pPlayer->GetDefaultFOV() || (gpGlobals->curtime < m_zoomFullyActiveTime))
|
||||
{
|
||||
fSpread += 0.025;
|
||||
}
|
||||
|
||||
return fSpread;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CWeaponScout::PrimaryAttack( void )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if (pPlayer == NULL)
|
||||
return;
|
||||
|
||||
if ( !CSBaseGunFire( GetCSWpnData().m_flCycleTime, m_weaponMode ) )
|
||||
return;
|
||||
|
||||
if ( m_weaponMode == Secondary_Mode )
|
||||
{
|
||||
float midFOVdistance = fabs( pPlayer->GetFOV() - (float)cScoutMidZoomFOV );
|
||||
float farFOVdistance = fabs( pPlayer->GetFOV() - (float)cScoutMaxZoomFOV );
|
||||
|
||||
if ( midFOVdistance < farFOVdistance )
|
||||
{
|
||||
pPlayer->m_iLastZoom = cScoutMidZoomFOV;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPlayer->m_iLastZoom = cScoutMaxZoomFOV;
|
||||
}
|
||||
|
||||
// #ifndef CLIENT_DLL
|
||||
pPlayer->m_bResumeZoom = true;
|
||||
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV(), 0.05f );
|
||||
m_weaponMode = Primary_Mode;
|
||||
// #endif
|
||||
}
|
||||
|
||||
QAngle angle = pPlayer->GetPunchAngle();
|
||||
angle.x -= 2;
|
||||
pPlayer->SetPunchAngle( angle );
|
||||
}
|
||||
|
||||
|
||||
float CWeaponScout::GetMaxSpeed() const
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if (pPlayer == NULL)
|
||||
{
|
||||
Assert(pPlayer != NULL);
|
||||
return BaseClass::GetMaxSpeed();
|
||||
}
|
||||
|
||||
if ( pPlayer->GetFOV() == pPlayer->GetDefaultFOV() )
|
||||
return BaseClass::GetMaxSpeed();
|
||||
else
|
||||
return 220; // zoomed in.
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponScout::Reload()
|
||||
{
|
||||
m_weaponMode = Primary_Mode;
|
||||
return BaseClass::Reload();
|
||||
|
||||
}
|
||||
|
||||
bool CWeaponScout::Deploy()
|
||||
{
|
||||
m_weaponMode = Primary_Mode;
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponSG550 C_WeaponSG550
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
#include "KeyValues.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponSG550 : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponSG550, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponSG550();
|
||||
|
||||
virtual void Spawn();
|
||||
virtual void SecondaryAttack();
|
||||
virtual void PrimaryAttack();
|
||||
virtual bool Reload();
|
||||
virtual bool Deploy();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
virtual float GetMaxSpeed() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_SG550; }
|
||||
|
||||
|
||||
private:
|
||||
CWeaponSG550( const CWeaponSG550 & );
|
||||
|
||||
float m_flLastFire;
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponSG550, DT_WeaponSG550 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponSG550, DT_WeaponSG550 )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#if defined CLIENT_DLL
|
||||
BEGIN_PREDICTION_DATA( CWeaponSG550 )
|
||||
DEFINE_FIELD( m_flLastFire, FIELD_FLOAT ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_sg550, CWeaponSG550 );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_sg550 );
|
||||
|
||||
|
||||
|
||||
CWeaponSG550::CWeaponSG550()
|
||||
{
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
void CWeaponSG550::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
m_flAccuracy = 0.98;
|
||||
}
|
||||
|
||||
|
||||
void CWeaponSG550::SecondaryAttack()
|
||||
{
|
||||
const float kZoomTime = 0.10f;
|
||||
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if (pPlayer->GetFOV() == pPlayer->GetDefaultFOV())
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, 40, kZoomTime );
|
||||
m_weaponMode = Secondary_Mode;
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyAltSwitch;
|
||||
}
|
||||
else if (pPlayer->GetFOV() == 40)
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, 15, kZoomTime );
|
||||
m_weaponMode = Secondary_Mode;
|
||||
}
|
||||
else if (pPlayer->GetFOV() == 15)
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV(), kZoomTime );
|
||||
m_weaponMode = Primary_Mode;
|
||||
}
|
||||
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// If this isn't guarded, the sound will be emitted twice, once by the server and once by the client.
|
||||
// Let the server play it since if only the client plays it, it's liable to get played twice cause of
|
||||
// a prediction error. joy.
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [tj] Playing this from the player so that we don't try to play the sound outside the level.
|
||||
//=============================================================================
|
||||
if ( GetPlayerOwner() )
|
||||
{
|
||||
GetPlayerOwner()->EmitSound( "Default.Zoom" ); // zoom sound.
|
||||
}
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
// let the bots hear the rifle zoom
|
||||
IGameEvent * event = gameeventmanager->CreateEvent( "weapon_zoom" );
|
||||
if( event )
|
||||
{
|
||||
event->SetInt( "userid", pPlayer->GetUserID() );
|
||||
gameeventmanager->FireEvent( event );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 0.3f;
|
||||
m_zoomFullyActiveTime = gpGlobals->curtime + 0.3; // The worst zoom time from above.
|
||||
}
|
||||
|
||||
float CWeaponSG550::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
float fSpread = 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
fSpread = 0.45f * (1 - m_flAccuracy);
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
fSpread = 0.15f;
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
fSpread = 0.04f * (1 - m_flAccuracy);
|
||||
else
|
||||
fSpread = 0.05f * (1 - m_flAccuracy);
|
||||
|
||||
// If we are not zoomed in, or we have very recently zoomed and are still transitioning, the bullet diverts more.
|
||||
if (pPlayer->GetFOV() == pPlayer->GetDefaultFOV() || (gpGlobals->curtime < m_zoomFullyActiveTime))
|
||||
fSpread += 0.025;
|
||||
|
||||
return fSpread;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CWeaponSG550::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
// Mark the time of this shot and determine the accuracy modifier based on the last shot fired...
|
||||
m_flAccuracy = 0.65 + (0.35) * (gpGlobals->curtime - m_flLastFire);
|
||||
|
||||
if (m_flAccuracy > 0.98)
|
||||
m_flAccuracy = 0.98;
|
||||
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
|
||||
if ( !CSBaseGunFire( GetCSWpnData().m_flCycleTime, m_weaponMode ) )
|
||||
return;
|
||||
|
||||
QAngle angle = pPlayer->GetPunchAngle();
|
||||
angle.x -= SharedRandomFloat("SG550PunchAngleX", 0.75, 1.25 ) + ( angle.x / 4 );
|
||||
angle.y += SharedRandomFloat("SG550PunchAngleY", -0.75, 0.75 );
|
||||
pPlayer->SetPunchAngle( angle );
|
||||
}
|
||||
|
||||
bool CWeaponSG550::Reload()
|
||||
{
|
||||
bool ret = BaseClass::Reload();
|
||||
|
||||
m_flAccuracy = 0.98;
|
||||
m_weaponMode = Primary_Mode;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CWeaponSG550::Deploy()
|
||||
{
|
||||
bool ret = BaseClass::Deploy();
|
||||
|
||||
m_flAccuracy = 0.98;
|
||||
m_weaponMode = Primary_Mode;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
float CWeaponSG550::GetMaxSpeed() const
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
|
||||
if ( !pPlayer || pPlayer->GetFOV() == 90 )
|
||||
return BaseClass::GetMaxSpeed();
|
||||
else
|
||||
return 150; // zoomed in
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponSG552 C_WeaponSG552
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponSG552 : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponSG552, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponSG552();
|
||||
|
||||
virtual void SecondaryAttack();
|
||||
virtual void PrimaryAttack();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
virtual float GetMaxSpeed() const;
|
||||
virtual bool Reload();
|
||||
virtual bool Deploy();
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_SG552; }
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
virtual bool HideViewModelWhenZoomed( void ) { return false; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
CWeaponSG552( const CWeaponSG552 & );
|
||||
|
||||
void SG552Fire( float flSpread, bool bZoomed );
|
||||
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponSG552, DT_WeaponSG552 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponSG552, DT_WeaponSG552 )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponSG552 )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_sg552, CWeaponSG552 );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_sg552 );
|
||||
|
||||
|
||||
|
||||
CWeaponSG552::CWeaponSG552()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CWeaponSG552::SecondaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if (pPlayer->GetFOV() == pPlayer->GetDefaultFOV())
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, 55, 0.2f );
|
||||
m_weaponMode = Secondary_Mode;
|
||||
}
|
||||
else if (pPlayer->GetFOV() == 55)
|
||||
{
|
||||
pPlayer->SetFOV( pPlayer, 0, 0.15f );
|
||||
m_weaponMode = Secondary_Mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
//FIXME: This seems wrong
|
||||
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV() );
|
||||
m_weaponMode = Primary_Mode;
|
||||
}
|
||||
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 0.3;
|
||||
}
|
||||
|
||||
float CWeaponSG552::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 0.035f + 0.45f * m_flAccuracy;
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 140)
|
||||
return 0.035f + 0.075f * m_flAccuracy;
|
||||
else
|
||||
return 0.02f * m_flAccuracy;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CWeaponSG552::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
bool bZoomed = pPlayer->GetFOV() < pPlayer->GetDefaultFOV();
|
||||
|
||||
float flCycleTime = GetCSWpnData().m_flCycleTime;
|
||||
|
||||
if ( bZoomed )
|
||||
flCycleTime = 0.135f;
|
||||
|
||||
if ( !CSBaseGunFire( flCycleTime, m_weaponMode ) )
|
||||
return;
|
||||
|
||||
// CSBaseGunFire can kill us, forcing us to drop our weapon, if we shoot something that explodes
|
||||
pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
pPlayer->KickBack (1, 0.45, 0.28, 0.04, 4.25, 2.5, 7);
|
||||
else if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
pPlayer->KickBack (1.25, 0.45, 0.22, 0.18, 6, 4, 5);
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
pPlayer->KickBack (0.6, 0.35, 0.2, 0.0125, 3.7, 2, 10);
|
||||
else
|
||||
pPlayer->KickBack (0.625, 0.375, 0.25, 0.0125, 4, 2.25, 9);
|
||||
}
|
||||
|
||||
|
||||
float CWeaponSG552::GetMaxSpeed() const
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
|
||||
if ( !pPlayer || pPlayer->GetFOV() == pPlayer->GetDefaultFOV() )
|
||||
return BaseClass::GetMaxSpeed();
|
||||
else
|
||||
return 200; // zoomed in.
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponSG552::Reload()
|
||||
{
|
||||
m_weaponMode = Primary_Mode;
|
||||
return BaseClass::Reload();
|
||||
}
|
||||
|
||||
bool CWeaponSG552::Deploy()
|
||||
{
|
||||
m_weaponMode = Primary_Mode;
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "gamerules.h"
|
||||
#include "npcevent.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "weapon_smokegrenade.h"
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
#include "items.h"
|
||||
#include "smokegrenade_projectile.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( SmokeGrenade, DT_SmokeGrenade )
|
||||
|
||||
BEGIN_NETWORK_TABLE(CSmokeGrenade, DT_SmokeGrenade)
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CSmokeGrenade )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_smokegrenade, CSmokeGrenade );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_smokegrenade );
|
||||
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
BEGIN_DATADESC( CSmokeGrenade )
|
||||
END_DATADESC()
|
||||
|
||||
void CSmokeGrenade::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer )
|
||||
{
|
||||
CSmokeGrenadeProjectile::Create( vecSrc, vecAngles, vecVel, angImpulse, pPlayer );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef WEAPON_SMOKEGRENADE_H
|
||||
#define WEAPON_SMOKEGRENADE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "weapon_basecsgrenade.h"
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#define CSmokeGrenade C_SmokeGrenade
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Smoke grenades
|
||||
//-----------------------------------------------------------------------------
|
||||
class CSmokeGrenade : public CBaseCSGrenade
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSmokeGrenade, CBaseCSGrenade );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CSmokeGrenade() {}
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_SMOKEGRENADE; }
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#else
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer );
|
||||
|
||||
#endif
|
||||
|
||||
CSmokeGrenade( const CSmokeGrenade & ) {}
|
||||
};
|
||||
|
||||
|
||||
#endif // WEAPON_SMOKEGRENADE_H
|
||||
@@ -0,0 +1,106 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponTMP C_WeaponTMP
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponTMP : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponTMP, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponTMP();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_TMP; }
|
||||
virtual bool IsSilenced( void ) const { return true; }
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
private:
|
||||
|
||||
CWeaponTMP( const CWeaponTMP & );
|
||||
|
||||
void DoFireEffects( void );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponTMP, DT_WeaponTMP )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponTMP, DT_WeaponTMP )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponTMP )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_tmp, CWeaponTMP );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_tmp );
|
||||
|
||||
|
||||
CWeaponTMP::CWeaponTMP()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
float CWeaponTMP::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 0.25f * m_flAccuracy;
|
||||
else
|
||||
return 0.03f * m_flAccuracy;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CWeaponTMP::PrimaryAttack( void )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( !CSBaseGunFire( GetCSWpnData().m_flCycleTime, Primary_Mode ) )
|
||||
return;
|
||||
|
||||
// CSBaseGunFire can kill us, forcing us to drop our weapon, if we shoot something that explodes
|
||||
pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
pPlayer->KickBack (1.1, 0.5, 0.35, 0.045, 4.5, 3.5, 6);
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
pPlayer->KickBack (0.8, 0.4, 0.2, 0.03, 3, 2.5, 7);
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
pPlayer->KickBack (0.7, 0.35, 0.125, 0.025, 2.5, 2, 10);
|
||||
else
|
||||
pPlayer->KickBack (0.725, 0.375, 0.15, 0.025, 2.75, 2.25, 9);
|
||||
}
|
||||
|
||||
void CWeaponTMP::DoFireEffects( void )
|
||||
{
|
||||
// TMP is silenced, so do nothing
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbasegun.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponUMP45 C_WeaponUMP45
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponUMP45 : public CWeaponCSBaseGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponUMP45, CWeaponCSBaseGun );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponUMP45();
|
||||
|
||||
virtual void Spawn();
|
||||
virtual void PrimaryAttack();
|
||||
virtual bool Deploy();
|
||||
virtual bool Reload();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_UMP45; }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
CWeaponUMP45( const CWeaponUMP45 & );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponUMP45, DT_WeaponUMP45 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponUMP45, DT_WeaponUMP45 )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponUMP45 )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_ump45, CWeaponUMP45 );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_ump45 );
|
||||
|
||||
|
||||
|
||||
CWeaponUMP45::CWeaponUMP45()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CWeaponUMP45::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
|
||||
m_flAccuracy = 0.0;
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponUMP45::Deploy()
|
||||
{
|
||||
bool ret = BaseClass::Deploy();
|
||||
|
||||
m_flAccuracy = 0.0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CWeaponUMP45::Reload()
|
||||
{
|
||||
bool ret = BaseClass::Reload();
|
||||
|
||||
m_flAccuracy = 0.0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
float CWeaponUMP45::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 0.24f * m_flAccuracy;
|
||||
else
|
||||
return 0.04f * m_flAccuracy;
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
void CWeaponUMP45::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if ( !CSBaseGunFire( GetCSWpnData().m_flCycleTime, Primary_Mode ) )
|
||||
return;
|
||||
|
||||
// CSBaseGunFire can kill us, forcing us to drop our weapon, if we shoot something that explodes
|
||||
pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
// Kick the gun based on the state of the player.
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
pPlayer->KickBack (0.125, 0.65, 0.55, 0.0475, 5.5, 4, 10);
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
pPlayer->KickBack (0.55, 0.3, 0.225, 0.03, 3.5, 2.5, 10);
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
pPlayer->KickBack (0.25, 0.175, 0.125, 0.02, 2.25, 1.25, 10);
|
||||
else
|
||||
pPlayer->KickBack (0.275, 0.2, 0.15, 0.0225, 2.5, 1.5, 10);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,395 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "fx_cs_shared.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponUSP C_WeaponUSP
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponUSP : public CWeaponCSBase
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponUSP, CWeaponCSBase );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponUSP();
|
||||
|
||||
virtual void Spawn();
|
||||
virtual void Precache();
|
||||
|
||||
virtual void PrimaryAttack();
|
||||
virtual void SecondaryAttack();
|
||||
virtual bool Deploy();
|
||||
virtual bool Holster( CBaseCombatWeapon *pSwitchingTo );
|
||||
virtual void Drop( const Vector &vecVelocity );
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
|
||||
virtual bool Reload();
|
||||
virtual void WeaponIdle();
|
||||
|
||||
// We overload this so we can translate all weapon activities to silenced versions.
|
||||
virtual bool SendWeaponAnim( int iActivity );
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_USP; }
|
||||
|
||||
// return true if this weapon has a silencer equipped
|
||||
virtual bool IsSilenced( void ) const { return m_bSilencerOn; }
|
||||
|
||||
virtual Activity GetDeployActivity( void );
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
virtual int GetMuzzleFlashStyle( void );
|
||||
#endif
|
||||
|
||||
virtual const char *GetWorldModel( void ) const;
|
||||
virtual int GetWorldModelIndex( void );
|
||||
|
||||
private:
|
||||
CWeaponUSP( const CWeaponUSP & );
|
||||
|
||||
CNetworkVar( bool, m_bSilencerOn );
|
||||
CNetworkVar( float, m_flDoneSwitchingSilencer ); // soonest time switching the silencer will be complete
|
||||
float m_flLastFire;
|
||||
|
||||
int m_silencedModelIndex;
|
||||
bool m_inPrecache;
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponUSP, DT_WeaponUSP )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponUSP, DT_WeaponUSP )
|
||||
#ifdef CLIENT_DLL
|
||||
RecvPropBool( RECVINFO( m_bSilencerOn ) ),
|
||||
RecvPropTime( RECVINFO( m_flDoneSwitchingSilencer ) ),
|
||||
#else
|
||||
SendPropBool( SENDINFO( m_bSilencerOn ) ),
|
||||
SendPropTime( SENDINFO( m_flDoneSwitchingSilencer ) ),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
BEGIN_PREDICTION_DATA( CWeaponUSP )
|
||||
DEFINE_PRED_FIELD( m_bSilencerOn, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_FIELD( m_flLastFire, FIELD_FLOAT ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_usp, CWeaponUSP );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_usp );
|
||||
|
||||
|
||||
Activity g_SilencedTranslations[][2] =
|
||||
{
|
||||
{ ACT_VM_RELOAD, ACT_VM_RELOAD_SILENCED },
|
||||
{ ACT_VM_PRIMARYATTACK, ACT_VM_PRIMARYATTACK_SILENCED },
|
||||
{ ACT_VM_DRAW, ACT_VM_DRAW_SILENCED },
|
||||
};
|
||||
|
||||
|
||||
|
||||
CWeaponUSP::CWeaponUSP()
|
||||
{
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
m_bSilencerOn = false;
|
||||
m_flDoneSwitchingSilencer = 0.0f;
|
||||
m_inPrecache = false;
|
||||
}
|
||||
|
||||
|
||||
void CWeaponUSP::Spawn()
|
||||
{
|
||||
//m_iDefaultAmmo = 12;
|
||||
m_flAccuracy = 0.92;
|
||||
m_bSilencerOn = false;
|
||||
m_weaponMode = Primary_Mode;
|
||||
m_flDoneSwitchingSilencer = 0.0f;
|
||||
|
||||
//FallInit();// get ready to fall down.
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
|
||||
void CWeaponUSP::Precache()
|
||||
{
|
||||
m_inPrecache = true;
|
||||
BaseClass::Precache();
|
||||
|
||||
m_silencedModelIndex = CBaseEntity::PrecacheModel( GetCSWpnData().m_szSilencerModel );
|
||||
m_inPrecache = false;
|
||||
}
|
||||
|
||||
|
||||
int CWeaponUSP::GetWorldModelIndex( void )
|
||||
{
|
||||
if ( !m_bSilencerOn || m_inPrecache )
|
||||
{
|
||||
return m_iWorldModelIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_silencedModelIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char * CWeaponUSP::GetWorldModel( void ) const
|
||||
{
|
||||
if ( !m_bSilencerOn || m_inPrecache )
|
||||
{
|
||||
return BaseClass::GetWorldModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetCSWpnData().m_szSilencerModel;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponUSP::Deploy()
|
||||
{
|
||||
m_flAccuracy = 0.92;
|
||||
m_flDoneSwitchingSilencer = 0.0f;
|
||||
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
bool CWeaponUSP::Holster( CBaseCombatWeapon *pSwitchingTo )
|
||||
{
|
||||
if ( gpGlobals->curtime < m_flDoneSwitchingSilencer )
|
||||
{
|
||||
// still switching the silencer. Cancel the switch.
|
||||
m_bSilencerOn = !m_bSilencerOn;
|
||||
m_weaponMode = m_bSilencerOn ? Secondary_Mode : Primary_Mode;
|
||||
SetWeaponModelIndex( GetWorldModel() );
|
||||
}
|
||||
|
||||
return BaseClass::Holster( pSwitchingTo );
|
||||
}
|
||||
|
||||
void CWeaponUSP::Drop( const Vector &vecVelocity )
|
||||
{
|
||||
if ( gpGlobals->curtime < m_flDoneSwitchingSilencer )
|
||||
{
|
||||
// still switching the silencer. Cancel the switch.
|
||||
m_bSilencerOn = !m_bSilencerOn;
|
||||
m_weaponMode = m_bSilencerOn ? Secondary_Mode : Primary_Mode;
|
||||
SetWeaponModelIndex( GetWorldModel() );
|
||||
}
|
||||
|
||||
BaseClass::Drop( vecVelocity );
|
||||
}
|
||||
|
||||
Activity CWeaponUSP::GetDeployActivity( void )
|
||||
{
|
||||
if( IsSilenced() )
|
||||
{
|
||||
return ACT_VM_DRAW_SILENCED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ACT_VM_DRAW;
|
||||
}
|
||||
}
|
||||
|
||||
void CWeaponUSP::SecondaryAttack()
|
||||
{
|
||||
if ( m_bSilencerOn )
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_DETACH_SILENCER );
|
||||
}
|
||||
else
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_ATTACH_SILENCER );
|
||||
}
|
||||
m_bSilencerOn = !m_bSilencerOn;
|
||||
m_weaponMode = m_bSilencerOn ? Secondary_Mode : Primary_Mode;
|
||||
m_flDoneSwitchingSilencer = gpGlobals->curtime + 3;
|
||||
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 3;
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 3;
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 3 );
|
||||
|
||||
SetWeaponModelIndex( GetWorldModel() );
|
||||
}
|
||||
|
||||
|
||||
float CWeaponUSP::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return 0.0f;
|
||||
|
||||
if ( m_bSilencerOn )
|
||||
{
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 1.3f * (1 - m_flAccuracy);
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
return 0.25f * (1 - m_flAccuracy);
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
return 0.125f * (1 - m_flAccuracy);
|
||||
else
|
||||
return 0.15f * (1 - m_flAccuracy);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
||||
return 1.2f * (1 - m_flAccuracy );
|
||||
else if (pPlayer->GetAbsVelocity().Length2D() > 5)
|
||||
return 0.225f * (1 - m_flAccuracy);
|
||||
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
||||
return 0.08f * (1 - m_flAccuracy);
|
||||
else
|
||||
return 0.1f * (1 - m_flAccuracy);
|
||||
}
|
||||
}
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
|
||||
void CWeaponUSP::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
float flCycleTime = GetCSWpnData().m_flCycleTime;
|
||||
|
||||
// Mark the time of this shot and determine the accuracy modifier based on the last shot fired...
|
||||
m_flAccuracy -= (0.275)*(0.3 - (gpGlobals->curtime - m_flLastFire));
|
||||
|
||||
if (m_flAccuracy > 0.92)
|
||||
m_flAccuracy = 0.92;
|
||||
else if (m_flAccuracy < 0.6)
|
||||
m_flAccuracy = 0.6;
|
||||
|
||||
m_flLastFire = gpGlobals->curtime;
|
||||
|
||||
if (m_iClip1 <= 0)
|
||||
{
|
||||
if ( m_bFireOnEmpty )
|
||||
{
|
||||
PlayEmptySound();
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
|
||||
m_bFireOnEmpty = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pPlayer->m_iShotsFired++;
|
||||
|
||||
m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + flCycleTime;
|
||||
|
||||
m_iClip1--;
|
||||
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
|
||||
if ( !m_bSilencerOn )
|
||||
{
|
||||
pPlayer->DoMuzzleFlash();
|
||||
}
|
||||
|
||||
FX_FireBullets(
|
||||
pPlayer->entindex(),
|
||||
pPlayer->Weapon_ShootPosition(),
|
||||
pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
|
||||
GetWeaponID(),
|
||||
m_weaponMode,
|
||||
CBaseEntity::GetPredictionRandomSeed() & 255,
|
||||
GetInaccuracy(),
|
||||
GetSpread());
|
||||
|
||||
if (!m_iClip1 && pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0)
|
||||
{
|
||||
// HEV suit - indicate out of ammo condition
|
||||
pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0);
|
||||
}
|
||||
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 2 );
|
||||
|
||||
// update accuracy
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[m_weaponMode];
|
||||
|
||||
QAngle angle = pPlayer->GetPunchAngle();
|
||||
angle.x -= 2;
|
||||
pPlayer->SetPunchAngle( angle );
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponUSP::Reload()
|
||||
{
|
||||
if ( !DefaultPistolReload() )
|
||||
return false;
|
||||
|
||||
m_flAccuracy = 0.92;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWeaponUSP::WeaponIdle()
|
||||
{
|
||||
if (m_flTimeWeaponIdle > gpGlobals->curtime)
|
||||
return;
|
||||
|
||||
// only idle if the slid isn't back
|
||||
if (m_iClip1 != 0)
|
||||
{
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 6.0 );
|
||||
}
|
||||
}
|
||||
|
||||
bool CWeaponUSP::SendWeaponAnim( int iActivity )
|
||||
{
|
||||
// Translate the activity?
|
||||
if ( m_bSilencerOn )
|
||||
{
|
||||
for ( int i=0; i < ARRAYSIZE( g_SilencedTranslations ); i++ )
|
||||
{
|
||||
if ( g_SilencedTranslations[i][0] == iActivity )
|
||||
{
|
||||
iActivity = g_SilencedTranslations[i][1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BaseClass::SendWeaponAnim( iActivity );
|
||||
}
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
int CWeaponUSP::GetMuzzleFlashStyle( void )
|
||||
{
|
||||
if( m_bSilencerOn )
|
||||
{
|
||||
return CS_MUZZLEFLASH_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CS_MUZZLEFLASH_NORM;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,304 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_csbase.h"
|
||||
#include "fx_cs_shared.h"
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define CWeaponXM1014 C_WeaponXM1014
|
||||
#include "c_cs_player.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "cs_player.h"
|
||||
#include "te_shotgun_shot.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CWeaponXM1014 : public CWeaponCSBase
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponXM1014, CWeaponCSBase );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponXM1014();
|
||||
|
||||
virtual void Spawn();
|
||||
virtual void PrimaryAttack();
|
||||
virtual bool Reload();
|
||||
virtual void WeaponIdle();
|
||||
|
||||
virtual float GetInaccuracy() const;
|
||||
virtual float GetSpread() const;
|
||||
|
||||
virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_XM1014; }
|
||||
|
||||
private:
|
||||
|
||||
CWeaponXM1014( const CWeaponXM1014 & );
|
||||
|
||||
float m_flPumpTime;
|
||||
CNetworkVar( int, m_reloadState ); // special reload state for shotgun
|
||||
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponXM1014, DT_WeaponXM1014 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponXM1014, DT_WeaponXM1014 )
|
||||
#ifdef CLIENT_DLL
|
||||
RecvPropInt( RECVINFO( m_reloadState ) )
|
||||
#else
|
||||
SendPropInt( SENDINFO( m_reloadState ), 2, SPROP_UNSIGNED )
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#if defined(CLIENT_DLL)
|
||||
BEGIN_PREDICTION_DATA( CWeaponXM1014 )
|
||||
DEFINE_PRED_FIELD( m_reloadState, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_xm1014, CWeaponXM1014 );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_xm1014 );
|
||||
|
||||
|
||||
CWeaponXM1014::CWeaponXM1014()
|
||||
{
|
||||
m_flPumpTime = 0;
|
||||
m_reloadState = 0;
|
||||
}
|
||||
|
||||
void CWeaponXM1014::Spawn()
|
||||
{
|
||||
//m_iDefaultAmmo = M3_DEFAULT_GIVE;
|
||||
//FallInit();// get ready to fall
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
float CWeaponXM1014::GetInaccuracy() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
return 0.0f;
|
||||
else
|
||||
return BaseClass::GetInaccuracy();
|
||||
}
|
||||
|
||||
float CWeaponXM1014::GetSpread() const
|
||||
{
|
||||
if ( weapon_accuracy_model.GetInt() == 1 )
|
||||
return 0.0725f;
|
||||
|
||||
return GetCSWpnData().m_fSpread[Primary_Mode];
|
||||
}
|
||||
|
||||
void CWeaponXM1014::PrimaryAttack()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
float flCycleTime = GetCSWpnData().m_flCycleTime;
|
||||
|
||||
// don't fire underwater
|
||||
if (pPlayer->GetWaterLevel() == 3)
|
||||
{
|
||||
PlayEmptySound( );
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.15;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_iClip1 <= 0)
|
||||
{
|
||||
Reload();
|
||||
|
||||
if (m_iClip1 == 0)
|
||||
{
|
||||
PlayEmptySound( );
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.25;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
||||
|
||||
//pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME;
|
||||
//pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH;
|
||||
|
||||
m_iClip1--;
|
||||
pPlayer->DoMuzzleFlash();
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
// Dispatch the FX right away with full accuracy.
|
||||
float flCurAttack = CalculateNextAttackTime( flCycleTime );
|
||||
FX_FireBullets(
|
||||
pPlayer->entindex(),
|
||||
pPlayer->Weapon_ShootPosition(),
|
||||
pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
|
||||
GetWeaponID(),
|
||||
Primary_Mode,
|
||||
CBaseEntity::GetPredictionRandomSeed() & 255, // wrap it for network traffic so it's the same between client and server
|
||||
GetInaccuracy(),
|
||||
GetSpread(), // flSpread
|
||||
flCurAttack );
|
||||
|
||||
if (!m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0)
|
||||
{
|
||||
// HEV suit - indicate out of ammo condition
|
||||
pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0);
|
||||
}
|
||||
|
||||
if (m_iClip1 != 0)
|
||||
m_flPumpTime = gpGlobals->curtime + 0.5;
|
||||
|
||||
if (m_iClip1 != 0)
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 2.5 );
|
||||
else
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 0.25 );
|
||||
m_reloadState = 0;
|
||||
|
||||
// update accuracy
|
||||
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[Primary_Mode];
|
||||
|
||||
// Update punch angles.
|
||||
QAngle angle = pPlayer->GetPunchAngle();
|
||||
|
||||
if ( pPlayer->GetFlags() & FL_ONGROUND )
|
||||
{
|
||||
angle.x -= SharedRandomInt( "XM1014PunchAngleGround", 3, 5 );
|
||||
}
|
||||
else
|
||||
{
|
||||
angle.x -= SharedRandomInt( "XM1014PunchAngleAir", 7, 10 );
|
||||
}
|
||||
|
||||
pPlayer->SetPunchAngle( angle );
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponXM1014::Reload()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return false;
|
||||
|
||||
if (pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 || m_iClip1 == GetMaxClip1())
|
||||
return true;
|
||||
|
||||
// don't reload until recoil is done
|
||||
if (m_flNextPrimaryAttack > gpGlobals->curtime)
|
||||
return true;
|
||||
|
||||
//MIKETODO: shotgun reloading (wait until we get content)
|
||||
|
||||
// check to see if we're ready to reload
|
||||
if (m_reloadState == 0)
|
||||
{
|
||||
pPlayer->SetAnimation( PLAYER_RELOAD );
|
||||
|
||||
SendWeaponAnim( ACT_SHOTGUN_RELOAD_START );
|
||||
m_reloadState = 1;
|
||||
pPlayer->m_flNextAttack = gpGlobals->curtime + 0.5;
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 0.5 );
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.5;
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 0.5;
|
||||
|
||||
#ifdef GAME_DLL
|
||||
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD_START );
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (m_reloadState == 1)
|
||||
{
|
||||
if (m_flTimeWeaponIdle > gpGlobals->curtime)
|
||||
return true;
|
||||
// was waiting for gun to move to side
|
||||
m_reloadState = 2;
|
||||
|
||||
SendWeaponAnim( ACT_VM_RELOAD );
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 0.5 );
|
||||
#ifdef GAME_DLL
|
||||
if ( m_iClip1 == 6 )
|
||||
{
|
||||
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD_END );
|
||||
}
|
||||
else
|
||||
{
|
||||
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD_LOOP );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add them to the clip
|
||||
m_iClip1 += 1;
|
||||
|
||||
#ifdef GAME_DLL
|
||||
SendReloadEvents();
|
||||
#endif
|
||||
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
|
||||
if ( pPlayer )
|
||||
pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType );
|
||||
|
||||
m_reloadState = 1;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CWeaponXM1014::WeaponIdle()
|
||||
{
|
||||
CCSPlayer *pPlayer = GetPlayerOwner();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
if (m_flPumpTime && m_flPumpTime < gpGlobals->curtime)
|
||||
{
|
||||
// play pumping sound
|
||||
m_flPumpTime = 0;
|
||||
}
|
||||
|
||||
if (m_flTimeWeaponIdle < gpGlobals->curtime)
|
||||
{
|
||||
if (m_iClip1 == 0 && m_reloadState == 0 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ))
|
||||
{
|
||||
Reload( );
|
||||
}
|
||||
else if (m_reloadState != 0)
|
||||
{
|
||||
if (m_iClip1 != 7 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ))
|
||||
{
|
||||
Reload( );
|
||||
}
|
||||
else
|
||||
{
|
||||
// reload debounce has timed out
|
||||
//MIKETODO: shotgun anims
|
||||
SendWeaponAnim( ACT_SHOTGUN_RELOAD_FINISH );
|
||||
|
||||
// play cocking sound
|
||||
m_reloadState = 0;
|
||||
SetWeaponIdleTime( gpGlobals->curtime + 1.5 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_IDLE );
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user