This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions
+727
View File
@@ -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
+75
View File
@@ -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
+109
View File
@@ -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
+40
View File
@@ -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
+490
View File
@@ -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 ];
}
+402
View File
@@ -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();
}
+195
View File
@@ -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
+704
View File
@@ -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];
}
+251
View File
@@ -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_
+604
View File
@@ -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;
}
+167
View File
@@ -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
+246
View File
@@ -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_
+207
View File
@@ -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;
}
+83
View File
@@ -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
+210
View File
@@ -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
+57
View File
@@ -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 )
{
}
//-----------------------------------------------------------------------------
+55
View File
@@ -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
+147
View File
@@ -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
+89
View File
@@ -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
+537
View File
@@ -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
+410
View File
@@ -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();
}
}
+824
View File
@@ -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
+943
View File
@@ -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
+82
View File
@@ -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
+67
View File
@@ -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 ) );
+261
View File
@@ -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
+80
View File
@@ -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
//=============================================================================
}
+455
View File
@@ -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
}
+192
View File
@@ -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
+345
View File
@@ -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
}
+47
View File
@@ -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
+103
View File
@@ -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 );
}
+160
View File
@@ -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();
}
+306
View File
@@ -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 isnt 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
+221
View File
@@ -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
+289
View File
@@ -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 &centerPoint, 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
+218
View File
@@ -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 );
}
}
+58
View File
@@ -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
+235
View File
@@ -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 );
}
+317
View File
@@ -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
+243
View File
@@ -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 );
}
+202
View File
@@ -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 );
}
}
+60
View File
@@ -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
+49
View File
@@ -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
+213
View File
@@ -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
}
+114
View File
@@ -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);
}
+369
View File
@@ -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 );
}
}
}
+67
View File
@@ -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
+50
View File
@@ -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
+517
View File
@@ -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;
}
+81
View File
@@ -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
+105
View File
@@ -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);
}
+293
View File
@@ -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 );
}
}
}
+351
View File
@@ -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
+130
View File
@@ -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);
}
+129
View File
@@ -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);
}
+204
View File
@@ -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 );
}
}
+97
View File
@@ -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);
}
+220
View File
@@ -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();
}
+214
View File
@@ -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
}
+170
View File
@@ -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
+52
View File
@@ -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
+106
View File
@@ -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
}
+132
View File
@@ -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);
}
+395
View File
@@ -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
+304
View File
@@ -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 );
}
}
}