This commit is contained in:
nephacks
2025-06-04 03:22:50 +02:00
parent f234f23848
commit f12416cffd
14243 changed files with 6446499 additions and 26 deletions
File diff suppressed because it is too large Load Diff
+133
View File
@@ -0,0 +1,133 @@
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#if !defined ( ACHIEVEMENTS_CS_H )
#define ACHIEVEMENTS_CS_H
#include "cbase.h"
#include "cs_gamestats_shared.h"
#include "baseachievement.h"
#ifdef _PS3
#include "steam/steam_api.h"
#endif
#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;
};
//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;
}
CSStatType_t GetStatId(void)
{
return m_StatId;
}
private:
virtual void Init()
{
SetFlags( ACH_SAVE_GLOBAL );
}
void OnPlayerStatsUpdate( int nUserSlot );
CSStatType_t m_StatId;
};
#if defined (_X360)
static const int NumXboxMappedAchievements = 11; // number of xbox achievements that have a one to one correspondence with a medal
static const int MedalToXBox[NumXboxMappedAchievements][2] = { { CSEnemyKillsHigh, ACHIEVEMENT_KILL_ENEMY_HIGH },
{ CSGiveDamageLow, ACHIEVEMENT_GIVE_DAMAGE_LOW },
{ CSMoneyEarnedLow, ACHIEVEMENT_EARN_MONEY_LOW },
{ CSGunGameProgressiveRampage, ACHIEVEMENT_GUN_GAME_RAMPAGE },
{ CSHeadshots, ACHIEVEMENT_HEADSHOTS },
{ CSFlawlessVictory, ACHIEVEMENT_FLAWLESS_VICTORY },
{ CSDominationsLow, ACHIEVEMENT_DOMINATIONS_LOW },
{ CSKillWithEveryWeapon, ACHIEVEMENT_KILL_WITH_EVERY_WEAPON },
{ CSKillEnemyLastBullet, ACHIEVEMENT_KILL_ENEMY_LAST_BULLET },
{ CSKillEnemyTerrTeamBeforeBombPlant, ACHIEVEMENT_GUN_GAME_FIRST_THING_FIRST },
{ CSGGRoundsHigh, ACHIEVEMENT_GUN_GAME_ROUNDS_HIGH }};
class CAchievementListener : public CAutoGameSystem, public CGameEventListener
{
public:
CAchievementListener();
virtual bool Init();
protected:
void FireGameEvent( IGameEvent *event );
};
#endif
extern CAchievementMgr g_AchievementMgrCS; // global achievement mgr for CS
#endif // CLIENT_DLL
#endif // ACHIEVEMENTS_CS_H
@@ -0,0 +1,657 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "basecsgrenade_projectile.h"
extern ConVar sv_gravity;
#ifdef CLIENT_DLL
#include "c_cs_player.h"
#include "hltvcamera.h"
#include "in_buttons.h"
#include <vgui/IInput.h>
#include "vgui_controls/Controls.h"
#else
#include "bot_manager.h"
#include "cs_player.h"
#include "soundent.h"
#include "te_effect_dispatch.h"
#include "keyvalues.h"
#include "cs_gamestats.h"
#include "cs_simple_hostage.h"
#include "Effects/chicken.h"
BEGIN_DATADESC( CBaseCSGrenadeProjectile )
DEFINE_THINKFUNC( DangerSoundThink ),
END_DATADESC()
#define GRENADE_FAILSAFE_MAX_BOUNCES 20
#endif
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
#ifdef CLIENT_DLL
extern ConVar spec_show_xray;
extern ConVar sv_grenade_trajectory;
extern ConVar sv_grenade_trajectory_time_spectator;
extern ConVar sv_grenade_trajectory_thickness;
extern ConVar sv_grenade_trajectory_dash;
#endif
IMPLEMENT_NETWORKCLASS_ALIASED( BaseCSGrenadeProjectile, DT_BaseCSGrenadeProjectile )
BEGIN_NETWORK_TABLE( CBaseCSGrenadeProjectile, DT_BaseCSGrenadeProjectile )
#ifdef CLIENT_DLL
RecvPropVector( RECVINFO( m_vInitialVelocity ) ),
RecvPropInt( RECVINFO( m_nBounces ) )
#else
SendPropVector( SENDINFO( m_vInitialVelocity ),
20, // nbits
0, // flags
-3000, // low value
3000 // high value
),
SendPropInt( SENDINFO( m_nBounces ) )
#endif
END_NETWORK_TABLE()
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseCSGrenadeProjectile::~CBaseCSGrenadeProjectile()
{
flNextTrailLineTime = gpGlobals->curtime;
CreateGrenadeTrail();
}
void CBaseCSGrenadeProjectile::PostDataUpdate( DataUpdateType_t type )
{
BaseClass::PostDataUpdate( type );
//C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
if ( type == DATA_UPDATE_CREATED )
{
SetNextClientThink( gpGlobals->curtime );
vecLastTrailLinePos = GetLocalOrigin();
flNextTrailLineTime = gpGlobals->curtime + 0.1;
// 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 );
// IGameEvent * event = gameeventmanager->CreateEvent( "grenade_projectile_created" );
// C_CSPlayer *pPlayer = dynamic_cast<C_CSPlayer*>( GetThrower() );
// if( event && pPlayer )
// {
// event->SetInt( "owneruserid", pPlayer ? pPlayer->GetUserID() : 0 );
// event->SetInt( "grenade", GetGrenadeType() );
// gameeventmanager->FireEvent( event );
// }
//if ( pLocalPlayer )
// pLocalPlayer->NotifyPlayerOfThrownGrenade( this, GetThrower(), GetGrenadeType() );
}
else
{
}
}
void CBaseCSGrenadeProjectile::ClientThink( void )
{
BaseClass::ClientThink();
SetNextClientThink( gpGlobals->curtime );
if ( flNextTrailLineTime <= gpGlobals->curtime )
{
CreateGrenadeTrail();
}
}
void CBaseCSGrenadeProjectile::CreateGrenadeTrail( void )
{
C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
if ( !pLocalPlayer )
return;
if ( flNextTrailLineTime <= gpGlobals->curtime )
{
bool bRenderForSpectator = CanSeeSpectatorOnlyTools() && spec_show_xray.GetInt();
if ( sv_grenade_trajectory_time_spectator.GetFloat() > 0.0f && sv_grenade_trajectory.GetInt() == 0 && pLocalPlayer && ( bRenderForSpectator || ( !pLocalPlayer->IsAlive() && ( pLocalPlayer->GetObserverMode() > OBS_MODE_FREEZECAM ) ) ) )
{
bool bRender = false;
if ( ( GetTeamNumber() == TEAM_CT ) && ( bRenderForSpectator || ( pLocalPlayer->GetTeamNumber() == TEAM_CT ) ) )
bRender = true;
else if ( ( GetTeamNumber() == TEAM_TERRORIST ) && ( bRenderForSpectator || ( pLocalPlayer->GetTeamNumber() == TEAM_TERRORIST ) ) )
bRender = true;
if ( bRender )
{
// Grenade trails for spectators
//CInterpolatedVar< Vector > &interpolator = GetOriginInterpolator();
QAngle angGrTrajAngles;
Vector vec3tempOrientation = ( vecLastTrailLinePos - GetLocalOrigin() );
VectorAngles( vec3tempOrientation, angGrTrajAngles );
float flGrTraThickness = sv_grenade_trajectory_thickness.GetFloat();
Vector vec3_GrTrajMin = Vector( 0, -flGrTraThickness, -flGrTraThickness );
Vector vec3_GrTrajMax = Vector( vec3tempOrientation.Length(), flGrTraThickness, flGrTraThickness );
bool bDotted = ( sv_grenade_trajectory_dash.GetInt() && ( fmod( gpGlobals->curtime, 0.1f ) < 0.05f ) );
Color traceColor;
if ( GetTeamNumber() == TEAM_CT )
{
traceColor[0] = 114;
traceColor[1] = 155;
traceColor[2] = 221;
}
else
{
traceColor[0] = 224;
traceColor[1] = 175;
traceColor[2] = 86;
}
if ( bDotted )
{
traceColor[0] /= 10;
traceColor[1] /= 10;
traceColor[2] /= 10;
}
//Add extruded box shapes to glow pass to build the arc
GlowObjectManager().AddGlowBox( GetLocalOrigin(), angGrTrajAngles, vec3_GrTrajMin, vec3_GrTrajMax, traceColor, sv_grenade_trajectory_time_spectator.GetFloat() );
//Make the grenade projectile itself glow
if ( !m_GlowObject.IsRendering() )
{
m_GlowObject.SetColor( Vector( traceColor[0] / 255.0f, traceColor[1] / 255.0f, traceColor[2] / 255.0f ) );
m_GlowObject.SetAlpha( 0.3f );
m_GlowObject.SetGlowAlphaCappedByRenderAlpha( true );
m_GlowObject.SetGlowAlphaFunctionOfMaxVelocity( 50.0f );
m_GlowObject.SetGlowAlphaMax( 0.3f );
m_GlowObject.SetRenderFlags( true, true );
}
}
}
vecLastTrailLinePos = GetLocalOrigin();
flNextTrailLineTime = gpGlobals->curtime + 0.05;
}
}
int CBaseCSGrenadeProjectile::DrawModel( int flags, const RenderableInstance_t &instance )
{
// 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, instance );
}
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::Precache()
{
BaseClass::Precache();
PrecacheEffect( "gunshotsplash" );
}
void CBaseCSGrenadeProjectile::Spawn( void )
{
Precache();
BaseClass::Spawn();
SetSolidFlags( FSOLID_NOT_STANDABLE );
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM );
SetSolid( SOLID_BBOX ); // So it will collide with physics props!
AddFlag( FL_GRENADE );
m_lastHitPlayer = NULL;
// smaller, cube bounding box so we rest on the ground
Vector min = Vector( -GRENADE_DEFAULT_SIZE, -GRENADE_DEFAULT_SIZE, -GRENADE_DEFAULT_SIZE );
Vector max = Vector( GRENADE_DEFAULT_SIZE, GRENADE_DEFAULT_SIZE, GRENADE_DEFAULT_SIZE );
SetSize( min, max );
if ( CollisionProp( ) )
CollisionProp( )->SetCollisionBounds( min, max );
m_nBounces = 0;
}
int CBaseCSGrenadeProjectile::UpdateTransmitState()
{
// always call ShouldTransmit() for grenades
return SetTransmitState( FL_EDICT_FULLCHECK );
}
int CBaseCSGrenadeProjectile::ShouldTransmit( const CCheckTransmitInfo *pInfo )
{
CBaseEntity *pRecipientEntity = CBaseEntity::Instance( pInfo->m_pClientEnt );
if ( pRecipientEntity->IsPlayer() )
{
CBasePlayer *pRecipientPlayer = static_cast<CBasePlayer*>( pRecipientEntity );
// always transmit to the thrower of the grenade
if ( pRecipientPlayer && ( (GetThrower() && pRecipientPlayer == GetThrower()) ||
pRecipientPlayer->GetTeamNumber() == TEAM_SPECTATOR) )
{
return FL_EDICT_ALWAYS;
}
}
return FL_EDICT_PVSCHECK;
}
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() != WL_NotInWater)
{
SetAbsVelocity( GetAbsVelocity() * 0.5 );
}
}
//Sets the time at which the grenade will explode
void CBaseCSGrenadeProjectile::SetDetonateTimerLength( float timer )
{
m_flDetonateTime = gpGlobals->curtime + timer;
}
unsigned int CBaseCSGrenadeProjectile::PhysicsSolidMaskForEntity( void ) const
{
if ( GetCollisionGroup() == COLLISION_GROUP_DEBRIS )
{
return ((CONTENTS_GRENADECLIP | MASK_SOLID) & ~CONTENTS_MONSTER);
}
else
{
return (CONTENTS_GRENADECLIP|MASK_SOLID|MASK_VISIBLE_AND_NPCS|CONTENTS_HITBOX) & ~(CONTENTS_DEBRIS);
}
}
void CBaseCSGrenadeProjectile::ResolveFlyCollisionCustom( trace_t &trace, Vector &vecMove )
{
const float kSleepVelocity = 20.0f;
const float kSleepVelocitySquared = kSleepVelocity * kSleepVelocity;
// Verify that we have an entity.
CBaseEntity *pEntity = trace.m_pEnt;
Assert( pEntity );
if ( pEntity )
{
CChicken *pChicken = dynamic_cast< CChicken* >( pEntity );
if (pChicken)
{
// hurt the chicken
CTakeDamageInfo info( this, this, 10, DMG_CLUB );
pChicken->DispatchTraceAttack( info, GetAbsVelocity().Normalized(), &trace );
ApplyMultiDamage();
return;
}
}
// 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( pEntity && FClassnameIs( pEntity, "func_breakable" ) )
{
breakthrough = true;
}
if( pEntity && FClassnameIs( pEntity, "func_breakable_surf" ) )
{
breakthrough = true;
}
if( pEntity && FClassnameIs( pEntity, "prop_physics_multiplayer" ) && pEntity->GetMaxHealth() > 0 && pEntity->m_takedamage == DAMAGE_YES )
{
breakthrough = true;
}
// this one is tricky because BounceTouch hits breakable propers before we hit this function and the damage is already applied there (CBaseGrenade::BounceTouch( CBaseEntity *pOther ))
// by the time we hit this, the prop hasn't been removed yet, but it broke, is set to not take anymore damage and is marked for deletion - we have to cover this case here
if( pEntity && FClassnameIs( pEntity, "prop_dynamic" ) && pEntity->GetMaxHealth() > 0 && (pEntity->m_takedamage == DAMAGE_YES || (pEntity->m_takedamage == DAMAGE_NO && pEntity->IsEFlagSet( EFL_KILLME ))) )
{
breakthrough = true;
}
if ( breakthrough )
{
CTakeDamageInfo info( this, this, 10, DMG_CLUB );
pEntity->DispatchTraceAttack( info, GetAbsVelocity().Normalized(), &trace );
ApplyMultiDamage();
if( pEntity->m_iHealth <= 0 )
{
// slow our flight a little bit
Vector vel = GetAbsVelocity();
vel *= 0.4;
SetAbsVelocity( vel );
return;
}
}
//Assume all surfaces have the same elasticity
float flSurfaceElasticity = 1.0;
//Don't bounce off of players with perfect elasticity
if ( pEntity && pEntity->IsPlayer() )
{
flSurfaceElasticity = 0.3f;
// and do slight damage to players on the opposite team
if ( GetTeamNumber() != pEntity->GetTeamNumber() )
{
CTakeDamageInfo info( this, GetThrower(), 2, DMG_GENERIC );
pEntity->TakeDamage( info );
}
}
//Don't bounce twice on a selection of problematic entities
bool bIsProjectile = dynamic_cast< CBaseCSGrenadeProjectile* >( pEntity ) != NULL;
if ( pEntity && !pEntity->IsWorld() && m_lastHitPlayer.Get() == pEntity )
{
bool bIsHostage = dynamic_cast< CHostage* >( pEntity ) != NULL;
if ( pEntity->IsPlayer() || bIsHostage || bIsProjectile )
{
//DevMsg( "Setting %s to DEBRIS, it is in group %i, it hit %s in group %i\n", this->GetClassname(), this->GetCollisionGroup(), pEntity->GetClassname(), pEntity->GetCollisionGroup() );
SetCollisionGroup( COLLISION_GROUP_DEBRIS );
if ( bIsProjectile )
{
//DevMsg( "Setting %s to DEBRIS, it is in group %i.\n", pEntity->GetClassname(), pEntity->GetCollisionGroup() );
pEntity->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
}
return;
}
}
if ( pEntity )
{
m_lastHitPlayer = pEntity;
}
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(), vecMove );
float flSpeedSqr = DotProduct( vecMove, vecMove );
bool bIsWeapon = dynamic_cast< CBaseCombatWeapon* >( pEntity ) != NULL;
// Stop if on ground or if we bounce and our velocity is really low (keeps it from bouncing infinitely)
if ( pEntity &&
( ( trace.plane.normal.z > 0.7f ) || (trace.plane.normal.z > 0.1f && flSpeedSqr < kSleepVelocitySquared) ) &&
( pEntity->IsStandable() || bIsProjectile || bIsWeapon || pEntity->IsWorld() )
)
{
// clip it again to emulate old behavior and keep it from bouncing up like crazy when you throw it at the ground on the first toss
if ( flSpeedSqr > 96000 )
{
float alongDist = DotProduct( vecAbsVelocity.Normalized(), trace.plane.normal );
if ( alongDist > 0.5f )
{
float flBouncePadding = (1.0f - alongDist) + 0.5f;
vecAbsVelocity *= flBouncePadding;
}
}
SetAbsVelocity( vecAbsVelocity );
if ( flSpeedSqr < kSleepVelocitySquared )
{
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 vecBaseDir = GetBaseVelocity();
if ( !vecBaseDir.IsZero() )
{
VectorNormalize( vecBaseDir );
Vector vecDelta = GetBaseVelocity() - vecAbsVelocity;
float flScale = vecDelta.Dot( vecBaseDir );
vecAbsVelocity += GetBaseVelocity() * flScale;
}
VectorScale( vecAbsVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, vecMove );
PhysicsPushEntity( vecMove, &trace );
}
}
else
{
SetAbsVelocity( vecAbsVelocity );
VectorScale( vecAbsVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, vecMove );
PhysicsPushEntity( vecMove, &trace );
}
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 );
}
}
OnBounced();
if (m_nBounces > GRENADE_FAILSAFE_MAX_BOUNCES )
{
//failsafe detonate after 20 bounces
SetAbsVelocity( vec3_origin );
DetonateOnNextThink();
SetNextThink( gpGlobals->curtime );
SetMoveType( MOVETYPE_NONE );
}
else
{
m_nBounces++;
}
}
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 );
}
// Add a row to ogs for the explosion of this grenade. Damage instances are recorded separately.
void CBaseCSGrenadeProjectile::RecordDetonation( void )
{
// I hate having to call this from so many places since half the grenades override the standard detonate and the rest dont...
// If this triggers, it's because either somebody changed the way some grenade code chains to base methods or it's taking an uncommon code path
// that needs to be investigated.
if ( m_bDetonationRecorded )
{
Warning( "Detonation of grenade '%s' attempted to record twice!\n", GetDebugName() );
Assert( 0 );
return;
}
CCSPlayer::StartNewBulletGroup();
SWeaponHitData *pHitData = new SWeaponHitData;
if ( pHitData->InitAsGrenadeDetonation( this, CCSPlayer::GetBulletGroup() ) )
{
CCS_GameStats.RecordWeaponHit( pHitData ); // submission deletes the struct.
m_bDetonationRecorded = true;
}
else
{
delete pHitData;
}
}
void CBaseCSGrenadeProjectile::Explode( trace_t *pTrace, int bitsDamageType )
{
RecordDetonation();
BaseClass::Explode( pTrace, bitsDamageType );
}
#endif // !CLIENT_DLL
@@ -0,0 +1,122 @@
//========= Copyright © 1996-2005, 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();
//virtual bool IsGrenadeProjectile( void ) { return true; };
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 );
CNetworkVar( int, m_nBounces );
#ifdef CLIENT_DLL
CBaseCSGrenadeProjectile() {}
CBaseCSGrenadeProjectile( const CBaseCSGrenadeProjectile& ) {}
virtual ~CBaseCSGrenadeProjectile();
virtual int DrawModel( int flags, const RenderableInstance_t &instance );
virtual void PostDataUpdate( DataUpdateType_t type );
virtual void ClientThink( void );
void CreateGrenadeTrail( void );
float m_flSpawnTime;
Vector vecLastTrailLinePos;
float flNextTrailLineTime;
#else
DECLARE_DATADESC();
CBaseCSGrenadeProjectile() : m_pWeaponInfo(NULL), m_bDetonationRecorded(false) {}
virtual void PostConstructor( const char *className );
virtual ~CBaseCSGrenadeProjectile();
virtual void Precache();
virtual int UpdateTransmitState();
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo );
//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 void OnBounced( void ) {}
virtual void Explode( trace_t *pTrace, int bitsDamageType );
virtual float GetShakeAmplitude( void ) { return 0.0f; }
virtual void Splash();
virtual GrenadeType_t GetGrenadeType( void ) { return GRENADE_TYPE_EXPLOSIVE; }
// 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
const CCSWeaponInfo *m_pWeaponInfo;
enum
{
GRENADE_EXTINGUISHED_INFERNO = 1 << 0,
};
uint8 m_unOGSExtraFlags; // Misc flags about the grenade's effect in game to report to ogs
EHANDLE m_lastHitPlayer;
void DetonateOnNextThink( void ) { m_flDetonateTime = 0.0f; }
virtual unsigned int PhysicsSolidMaskForEntity( void ) const;
protected:
//Set the time to detonate ( now + timer )
void SetDetonateTimerLength( float timer );
// Called when this grenade explodes. If your decended class overides some part of the detonation process
// and prevents detonate from being called, you need to call this to make ogs still records it.
void RecordDetonation( void );
bool m_bDetonationRecorded;
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
+116
View File
@@ -0,0 +1,116 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
// Author: Michael S. Booth (mike@turtlerockstudios.com), Leon Hartwig, 2003
#include "cbase.h"
#include "cs_shareddefs.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_isSmoke = false;
m_isFlashbang = false;
m_isMolotov = false;
m_isDecoy = false;
switch ( grenadeEntity->GetGrenadeType() )
{
case GRENADE_TYPE_EXPLOSIVE: m_radius = HEGrenadeRadius; break;
case GRENADE_TYPE_FLASH: m_radius = FlashbangGrenadeRadius; m_isFlashbang = true; break;
case GRENADE_TYPE_FIRE: m_radius = MolotovGrenadeRadius; m_isMolotov = true; break;
case GRENADE_TYPE_DECOY: m_radius = DecoyGrenadeRadius; m_isDecoy = true; break;
case GRENADE_TYPE_SMOKE: m_radius = SmokeGrenadeRadius; m_isSmoke = true; break;
case GRENADE_TYPE_SENSOR: m_radius = MolotovGrenadeRadius; m_isSensor = true; break;
default:
AssertMsg( 0, "Invalid grenade type!\n" );
m_radius = HEGrenadeRadius;
}
}
//--------------------------------------------------------------------------------------------------------------
/**
* 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
+58
View File
@@ -0,0 +1,58 @@
//========= Copyright © 1996-2005, 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
char *BotDifficultyName[] =
{
"EASY", "NORMAL", "HARD", "EXPERT", NULL
};
#else
extern char *BotDifficultyName[];
#endif
namespace BotProfileInputDevice
{
enum Device
{
GAMEPAD = 0,
KB_MOUSE = 1,
PS3_MOVE = 2,
HYDRA = 3,
SHARPSHOOTER = 4,
COUNT, // Auto list counter
FORCE_INT32 = 0x7FFFFFFF // Force the typedef to be int32
};
};
typedef BotProfileInputDevice::Device BotProfileDevice_t;
#endif // BOT_CONSTANTS_H
+496
View File
@@ -0,0 +1,496 @@
//========= Copyright © 1996-2005, 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 )
{
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())
{
AssertMsg(false, "Check console spew for Hiding Spot off the Nav Mesh errors.");
continue;
}
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 ];
}
+352
View File
@@ -0,0 +1,352 @@
//========= Copyright © 1996-2005, 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 )
{
{
SNPROF("Upkeep");
bot->Upkeep();
}
if (((gpGlobals->tickcount + bot->entindex()) % g_BotUpdateSkipCount) == 0)
{
{
SNPROF("ResetCommand");
bot->ResetCommand();
}
{
SNPROF("Bot Update");
bot->Update();
}
}
{
SNPROF("UpdatePlayer");
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();
m_activeGrenadeList.Remove( it );
delete ag;
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 )
{
int it = m_activeGrenadeList.Head();
while ( it != m_activeGrenadeList.InvalidIndex() )
{
ActiveGrenade *ag = m_activeGrenadeList[it];
int current = it;
it = m_activeGrenadeList.Next( it );
m_activeGrenadeList.Remove( current );
delete ag;
}
m_activeGrenadeList.PurgeAndDeleteElements();
}
//--------------------------------------------------------------------------------------------------------------
/**
* Return true if position is inside a smoke cloud
*/
bool CBotManager::IsInsideSmokeCloud( const Vector *pos, float radius )
{
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() + radius ))
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() && CSGameRules() )
{
float flLengthAdd = CSGameRules()->CheckTotalSmokedLength( smokeRadiusSq, ag->GetDetonationPosition(), from, to );
// get the totalSmokedLength and check to see if the line starts or stops in smoke. If it does this will return -1 and we should just bail early
if ( flLengthAdd == -1 )
return true;
totalSmokedLength += flLengthAdd;
}
}
// 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();
}
+193
View File
@@ -0,0 +1,193 @@
//========= Copyright © 1996-2005, 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;
//--------------------------------------------------------------------------------------------------------------
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; }
bool IsMolotov( void ) const { return m_isMolotov; }
bool IsDecoy( void ) const { return m_isDecoy; }
bool IsSensor( void ) const { return m_isSensor; }
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
bool m_isMolotov; ///< true if this is a molotov grenade
bool m_isDecoy; ///< true if this is a decoy grenade
bool m_isSensor; ///< true if this is a sensor 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, float radius ); ///< return true if sphere at position overlaps 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 );
ActiveGrenadeList m_activeGrenadeList;///< the list of active grenades the bots are aware of
private:
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
+852
View File
@@ -0,0 +1,852 @@
//========= Copyright © 1996-2005, 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() 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() 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 && queryTemplate->InheritsFrom( name ) )
{
return true;
}
}
return false;
}
void BotProfile::SetName( const char* name )
{
if ( name )
{
if ( m_name )
{
// Delete the current name if it exists
delete [] m_name;
}
m_name = CloneString( name );
}
}
const BotProfile* BotProfile::GetTemplate( int index ) const
{
if ( index > 0 && index < m_templates.Count() )
{
return m_templates[index];
}
return NULL;
}
void BotProfile::Clone( const BotProfile* source_profile )
{
if ( source_profile )
{
SetName( source_profile->GetName() );
for ( int device = 0; device < BotProfileInputDevice::COUNT; ++device )
{
m_aggression = source_profile->GetAggression();
m_skill = source_profile->GetSkill();
m_teamwork = source_profile->GetTeamwork();
m_aimFocusInitial = source_profile->GetAimFocusInitial();
m_aimFocusDecay = source_profile->GetAimFocusDecay();
m_aimFocusOffsetScale = source_profile->GetAimFocusOffsetScale();
m_aimFocusInterval = source_profile->GetAimFocusInterval();
m_weaponPreferenceCount = source_profile->GetWeaponPreferenceCount();
for( int i = 0; i < source_profile->GetWeaponPreferenceCount(); ++i )
{
m_weaponPreference[i] = source_profile->GetWeaponPreference(i);
}
m_cost = source_profile->GetCost();
m_skin = source_profile->GetSkin();
m_difficultyFlags = source_profile->GetDifficultyFlags();
m_voicePitch = source_profile->GetVoicePitch();
m_reactionTime = source_profile->GetReactionTime();
m_attackDelay = source_profile->GetAttackDelay();
m_lookAngleMaxAccelNormal = source_profile->GetLookAngleMaxAccelerationNormal();
m_lookAngleStiffnessNormal = source_profile->GetLookAngleStiffnessNormal();
m_lookAngleDampingNormal = source_profile->GetLookAngleDampingNormal();
m_lookAngleMaxAccelAttacking = source_profile->GetLookAngleMaxAccelerationAttacking();
m_lookAngleStiffnessAttacking = source_profile->GetLookAngleStiffnessAttacking();
m_lookAngleDampingAttacking = source_profile->GetLookAngleDampingAttacking();
}
m_teams = source_profile->GetTeams();
m_voiceBank = source_profile->GetVoiceBank();
m_prefersSilencer = source_profile->PrefersSilencer();
for ( int i = 0; i < source_profile->GetTemplatesCount(); ++i )
{
m_templates.AddToTail( source_profile->GetTemplate( i ) );
}
}
}
//--------------------------------------------------------------------------------------------------------------
/**
* 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 ( !V_stricmp( "AimFocusInitial", attributeName ) )
{
profile->m_aimFocusInitial = (float)atof( token );
}
else if ( !V_stricmp( "AimFocusDecay", attributeName ) )
{
profile->m_aimFocusDecay = (float)atof( token );
}
else if ( !V_stricmp( "AimFocusOffsetScale", attributeName ) )
{
profile->m_aimFocusOffsetScale = (float)atof( token );
}
else if ( !V_stricmp( "AimFocusInterval", attributeName ) )
{
profile->m_aimFocusInterval = (float)atof( token );
}
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 ) )
{
ParseWeaponPreference( isFirstWeaponPref, profile->m_weaponPreferenceCount, profile->m_weaponPreference, token );
}
else if ( !stricmp( "ReactionTime", attributeName ) )
{
profile->m_reactionTime = (float)atof( token );
}
else if ( !stricmp( "AttackDelay", attributeName ))
{
profile->m_attackDelay = (float)atof( token );
}
else if ( !stricmp( "Difficulty", attributeName ))
{
// override inheritance
ParseDifficultySetting( profile->m_difficultyFlags, token );
}
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 if ( !stricmp( "LookAngleMaxAccelNormal", attributeName ) )
{
profile->m_lookAngleMaxAccelNormal = atof( token );
}
else if ( !stricmp( "LookAngleStiffnessNormal", attributeName ) )
{
profile->m_lookAngleStiffnessNormal = atof( token );
}
else if ( !stricmp( "LookAngleDampingNormal", attributeName ) )
{
profile->m_lookAngleDampingNormal = atof( token );
}
else if ( !stricmp( "LookAngleMaxAccelAttacking", attributeName ) )
{
profile->m_lookAngleMaxAccelAttacking = atof( token );
}
else if ( !stricmp( "LookAngleStiffnessAttacking", attributeName ) )
{
profile->m_lookAngleStiffnessAttacking = atof( token );
}
else if ( !stricmp( "LookAngleDampingAttacking", attributeName ) )
{
profile->m_lookAngleDampingAttacking = atof( token );
}
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;
}
void BotProfileManager::ParseDifficultySetting( unsigned char &difficultyFlags, char* token)
{
// override inheritance
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 ))
{
difficultyFlags |= (1 << i);
}
}
if (c == NULL)
{
break;
}
token = c+1;
}
}
void BotProfileManager::ParseWeaponPreference( bool &isFirstWeaponPref, int &weaponPreferenceCount, CSWeaponID* weaponPreference, char* token )
{
// weapon preferences override parent prefs
if (isFirstWeaponPref)
{
isFirstWeaponPref = false;
weaponPreferenceCount = 0;
}
if ( !stricmp( token, "none" ))
{
weaponPreferenceCount = 0;
}
else
{
if (weaponPreferenceCount < BotProfile::MAX_WEAPON_PREFS)
{
weaponPreference[ weaponPreferenceCount++ ] = AliasToWeaponID( token );
}
}
}
//--------------------------------------------------------------------------------------------------------------
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, bool forceMatchHighestDifficulty ) const
{
// count up valid profiles
CUtlVector< const BotProfile * > profiles;
FOR_EACH_LL( m_profileList, it )
{
const BotProfile *profile = m_profileList[ it ];
// Match difficulty
if ( forceMatchHighestDifficulty )
{
if ( !profile->IsMaxDifficulty( difficulty ) )
{
continue;
}
}
else
{
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];
}
+424
View File
@@ -0,0 +1,424 @@
//========= Copyright © 1996-2005, 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_aimFocusInitial = 0.0f;
m_aimFocusDecay = 1.0f;
m_aimFocusOffsetScale = 0.0f;
m_aimFocusInterval = .5f;
m_cost = 0;
m_skin = 0;
m_difficultyFlags = 0;
m_voicePitch = 100;
m_reactionTime = 0.3f;
m_attackDelay = 0.0f;
m_lookAngleMaxAccelNormal = 0.0f;
m_lookAngleStiffnessNormal = 0.0f;
m_lookAngleDampingNormal = 0.0f;
m_lookAngleMaxAccelAttacking = 0.0f;
m_lookAngleStiffnessAttacking = 0.0f;
m_lookAngleDampingAttacking = 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() const;
float GetSkill() const;
float GetTeamwork() const;
float GetAimFocusInitial() const { return m_aimFocusInitial; }
float GetAimFocusDecay() const { return m_aimFocusDecay; }
float GetAimFocusOffsetScale() const { return m_aimFocusOffsetScale; }
float GetAimFocusInterval() const { return m_aimFocusInterval; }
CSWeaponID GetWeaponPreference(int i ) const;
const char *GetWeaponPreferenceAsString( int i ) const;
int GetWeaponPreferenceCount() const;
bool HasPrimaryPreference() const; ///< return true if this profile has a primary weapon preference
bool HasPistolPreference() const; ///< return true if this profile has a pistol weapon preference
int GetCost() const;
int GetSkin() const;
int GetMaxDifficulty() const; ///< return maximum difficulty flag value
bool IsDifficulty( BotDifficultyType diff ) const; ///< return true if this profile can be used for the given difficulty level
bool IsMaxDifficulty( BotDifficultyType diff ) const; ///< return true if this profile's highest difficulty matches the incoming difficulty level
int GetVoicePitch() const;
float GetReactionTime() const;
float GetAttackDelay() const;
int GetVoiceBank() const { return m_voiceBank; }
unsigned char GetDifficultyFlags() const;
int GetTeams( void ) const { return m_teams; }
float GetLookAngleMaxAccelerationNormal() const;
float GetLookAngleStiffnessNormal() const;
float GetLookAngleDampingNormal() const;
float GetLookAngleMaxAccelerationAttacking() const;
float GetLookAngleStiffnessAttacking() const;
float GetLookAngleDampingAttacking() const;
bool IsValidForTeam( int team ) const;
bool PrefersSilencer() const { return m_prefersSilencer; }
bool InheritsFrom( const char *name ) const;
void Clone( const BotProfile* source_profile );
void SetName( const char* name );
void SetVoicePitch( int pitch );
int GetTemplatesCount( void ) const { return m_templates.Count(); }
const BotProfile* GetTemplate( int index ) 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
float m_aimFocusInitial; // initial minimum aim error on first attack
float m_aimFocusDecay; // how quickly our focus error decays (scale/sec)
float m_aimFocusOffsetScale; // how much aim focus error we get based on maximum angle distance from our view angle
float m_aimFocusInterval; // how frequently we update our focus
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)
float m_lookAngleMaxAccelNormal; // Acceleration of look angle spring under normal conditions
float m_lookAngleStiffnessNormal; // Stiffness of look angle spring under normal conditions
float m_lookAngleDampingNormal; // Damping of look angle spring under normal conditions
float m_lookAngleMaxAccelAttacking; // Acceleration of look angle spring under attack conditions
float m_lookAngleStiffnessAttacking; // Stiffness of look angle spring under attack conditions
float m_lookAngleDampingAttacking; // Damping of look angle spring under attack conditions
CUtlVector< const BotProfile * > m_templates; ///< List of templates we inherit from
};
typedef CUtlLinkedList<BotProfile *> BotProfileList;
inline int BotProfile::GetMaxDifficulty() const
{
for ( int i = NUM_DIFFICULTY_LEVELS - 1; i >= BOT_EASY; --i )
{
if ( m_difficultyFlags & ( 1 << i ) )
{
return i;
}
}
return BOT_EASY;
}
inline bool BotProfile::IsDifficulty( BotDifficultyType diff ) const
{
return (m_difficultyFlags & (1 << diff)) ? true : false;
}
inline bool BotProfile::IsMaxDifficulty( BotDifficultyType diff ) const
{
return ( ( m_difficultyFlags >> diff ) == 1 );
}
inline float BotProfile::GetAggression() const
{
return m_aggression;
}
inline float BotProfile::GetSkill() const
{
return m_skill;
}
inline float BotProfile::GetTeamwork() const
{
return m_teamwork;
}
inline CSWeaponID BotProfile::GetWeaponPreference( int i ) const
{
return m_weaponPreference[ i ];
}
inline int BotProfile::GetWeaponPreferenceCount() const
{
return m_weaponPreferenceCount;
}
inline int BotProfile::GetCost() const
{
return m_cost;
}
inline int BotProfile::GetSkin() const
{
return m_skin;
}
inline int BotProfile::GetVoicePitch() const
{
return m_voicePitch;
}
inline float BotProfile::GetReactionTime() const
{
return m_reactionTime;
}
inline float BotProfile::GetAttackDelay() const
{
return m_attackDelay;
}
inline unsigned char BotProfile::GetDifficultyFlags() const
{
return m_difficultyFlags;
}
inline float BotProfile::GetLookAngleMaxAccelerationNormal() const
{
return m_lookAngleMaxAccelNormal;
}
inline float BotProfile::GetLookAngleStiffnessNormal( ) const
{
return m_lookAngleStiffnessNormal;
}
inline float BotProfile::GetLookAngleDampingNormal() const
{
return m_lookAngleDampingNormal;
}
inline float BotProfile::GetLookAngleMaxAccelerationAttacking() const
{
return m_lookAngleMaxAccelAttacking;
}
inline float BotProfile::GetLookAngleStiffnessAttacking() const
{
return m_lookAngleStiffnessAttacking;
}
inline float BotProfile::GetLookAngleDampingAttacking() const
{
return m_lookAngleDampingAttacking;
}
inline void BotProfile::SetVoicePitch( int pitch )
{
m_voicePitch = pitch;
}
/**
* 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_aimFocusInitial != baseline->m_aimFocusInitial )
m_aimFocusInitial = parent->m_aimFocusInitial;
if ( parent->m_aimFocusDecay != baseline->m_aimFocusDecay )
m_aimFocusDecay = parent->m_aimFocusDecay;
if ( parent->m_aimFocusOffsetScale != baseline->m_aimFocusOffsetScale )
m_aimFocusOffsetScale = parent->m_aimFocusOffsetScale;
if ( parent->m_aimFocusInterval != baseline->m_aimFocusInterval )
m_aimFocusInterval = parent->m_aimFocusInterval;
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, BotProfileDevice_t device, bool bAllowDupeNames = false ) 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 ( bAllowDupeNames == false && 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, bool forceMatchHighestDifficulty = false ) 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:
void ParseDifficultySetting( unsigned char &difficultyFlags, char* token);
void ParseWeaponPreference( bool &isFirstWeaponPref, int &weaponPreferenceCount, CSWeaponID* weaponPreference, char* token );
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_
+682
View File
@@ -0,0 +1,682 @@
//========= Copyright © 1996-2005, 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;
extern ConVar mp_randomspawn_dist;
extern ConVar mp_randomspawn_los;
//--------------------------------------------------------------------------------------------------------------
/**
* 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, bool bQueue )
{
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->GetPendingTeamNumber() == TEAM_SPECTATOR )
{
// bot has already been flagged for kicking
continue;
}
if ( !player->IsAlive() )
{
// Address issue with bots getting kicked during half-time (this was resulting in bots from the wrong team being kicked)
if ( player->CanKickFromTeam( kickTeam ) )
{
if ( bQueue )
{
// bots flagged as spectators will be kicked at the beginning of the next round restart
player->SetPendingTeamNum( TEAM_SPECTATOR );
}
else
{
// its a bot on the right team - kick it
engine->ServerCommand( UTIL_VarArgs( "kickid %d\n", engine->GetPlayerUserId( player->edict() ) ) );
}
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->GetPendingTeamNumber() == TEAM_SPECTATOR )
{
// bot has already been flagged for kicking
continue;
}
// Address issue with bots getting kicked during half-time (this was resulting in bots from the wrong team being kicked)
if ( player->CanKickFromTeam( kickTeam ) )
{
if ( bQueue )
{
// bots flagged as spectators will be kicked at the beginning of the next round restart
player->SetPendingTeamNum( TEAM_SPECTATOR );
}
else
{
// its a bot on the right team - kick it
engine->ServerCommand( UTIL_VarArgs( "kickid %d\n", engine->GetPlayerUserId( player->edict() ) ) );
}
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->GetWeaponType();
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;
}
//--------------------------------------------------------------------------------------------------------------
/**
* Return true if anyone on the given team can see the given spot
*/
bool UTIL_IsRandomSpawnFarEnoughAwayFromTeam( const Vector &spot, int team )
{
if ( mp_randomspawn_dist.GetInt() <= 0 )
return true;
if ( mp_randomspawn_los.GetInt() == 0 )
return true;
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;
if ( mp_randomspawn_dist.GetInt() > 0 && (player->GetAbsOrigin()).DistTo( spot ) < mp_randomspawn_dist.GetInt() )
{
//NDebugOverlay::Line( player->EyePosition(), spot + Vector( 0, 0, 32 ), 255, 0, 0, true, 4 );
//NDebugOverlay::Line( spot, spot + Vector( 0, 0, 64 ), 255, 128, 0, true, 4 );
continue;
}
else
{
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( 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.vmt" );
}
//------------------------------------------------------------------------------------------------------------
#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->GetFinalAimAngle(), &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;
}
+172
View File
@@ -0,0 +1,172 @@
//========= Copyright © 1996-2005, 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_goals;
extern ConVar cv_bot_defer_to_human_items;
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;
#if CS_CONTROLLABLE_BOTS_ENABLED
extern ConVar cv_bot_controllable;
#endif
#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, bool bQueue = false ); ///< kick a bot from the given team. If no bot exists on the team, return false, if bQueue is true kick will occur at round restart
extern bool UTIL_IsVisibleToTeam( const Vector &spot, int team ); ///< return true if anyone on the given team can see the given spot
extern bool UTIL_IsRandomSpawnFarEnoughAwayFromTeam( const Vector &spot, int team ); ///< return true if this spot is far enough away from everyone on specified team defined via
/// 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( 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 © 1996-2005, 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 © 1996-2005, 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_
+226
View File
@@ -0,0 +1,226 @@
//========= Copyright © 1996-2005, 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(PRINTF_FORMAT_STRING 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);
_vsnprintf( string[curstring], BufLen, format, argptr );
va_end (argptr);
return string[curstring];
}
//--------------------------------------------------------------------------------------------------------------
char * BufPrintf(char *buf, int& len, PRINTF_FORMAT_STRING const char *fmt, ...)
{
if (len <= 0)
return NULL;
va_list argptr;
va_start(argptr, fmt);
_vsnprintf(buf, len, fmt, argptr);
va_end(argptr);
// Make sure the buffer is null-terminated.
buf[ len - 1 ] = 0;
len -= strlen(buf);
return buf + strlen(buf);
}
#ifdef _WIN32
//--------------------------------------------------------------------------------------------------------------
wchar_t * BufWPrintf(wchar_t *buf, int& len, PRINTF_FORMAT_STRING const wchar_t *fmt, ...)
{
if (len <= 0)
return NULL;
va_list argptr;
va_start(argptr, fmt);
_vsnwprintf(buf, len, fmt, argptr);
va_end(argptr);
// Make sure the buffer is null-terminated.
buf[ len - 1 ] = 0;
len -= wcslen(buf);
return buf + wcslen(buf);
}
#endif
//--------------------------------------------------------------------------------------------------------------
#ifdef _WIN32
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;
}
#endif
// dgoodenough - PS3 needs this guy as well.
// PS3_BUILDFIX
#ifdef _PS3
const wchar_t * NumAsWString( int val )
{
const int BufLen = 16;
static wchar_t buf[BufLen];
char szBuf[BufLen];
Q_snprintf(szBuf, BufLen, "%d", val );
szBuf[BufLen - 1] = 0;
for ( int i = 0; i < BufLen; ++i )
{
buf[i] = szBuf[i];
}
return buf;
}
#endif
//--------------------------------------------------------------------------------------------------------------
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 ( !V_isspace( *p ) || V_isalnum( *p ) )
return true;
p++;
}
return false;
}
+106
View File
@@ -0,0 +1,106 @@
//========= Copyright © 1996-2005, 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;
}*/
//--------------------------------------------------------------------------------------------------------
/**
* Simple utility function to allocate memory and duplicate a wide string
*/
#ifdef _WIN32
extern inline wchar_t *CloneWString( const wchar_t *str );
// {
// wchar_t *cloneStr = new wchar_t [ wcslen(str)+1 ];
// wcscpy( cloneStr, str );
// return cloneStr;
// }
#endif
//--------------------------------------------------------------------------------------------------------------
/**
* 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
*/
#ifdef _WIN32
wchar_t * BufWPrintf(wchar_t *buf, int& len, PRINTF_FORMAT_STRING const wchar_t *fmt, ...);
#endif
//--------------------------------------------------------------------------------------------------------------
/**
* convenience function that prints an int into a static wchar_t*
*/
#ifdef _WIN32
const wchar_t * NumAsWString( int val );
#endif
// dgoodenough - PS3 needs this guy as well.
// PS3_BUILDFIX
#ifdef _PS3
const wchar_t * NumAsWString( int val );
#endif
//--------------------------------------------------------------------------------------------------------------
/**
* 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,60 @@
//-------------------------------------------------------------
// 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 = 4;
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 StillAlive_MaxHealthLeft = 10;
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 KillWhenAtMediumHealth_MaxHealth = 25;
const int GrenadeMultiKill_MinKills = 3;
const int BombMultiKill_MinKills = 5;
const float FastRoundWin_Time = 30.0f;
const int UnstoppableForce_Kills = 4;
const int ImmovableObject_Kills = 4;
//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 float KillEnemyNearHostage_MaxDistance = 250.0f;
const int GrenadeDamage_MinDamage = 200;
//const int Num_Required_Medals = 166; // earn this many medals, get the 12th xbla achievement (number of total medals displaying to user in game minus 1)
const int Num_Medalist_Required_Medals = 100; // earn this many medals, get the 12th xbla achievement (number of total medals displaying to user in game minus 1)
}
#endif // CS_ACHIEVEMENT_CONSTANTS_H
+277
View File
@@ -0,0 +1,277 @@
//========= Copyright © 1996-2005, 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
//=============================================================================
// set below to 1 to enable
#define ALL_WEARING_SAME_UNIFORM_ACHIEVEMENT 0
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,
CSPlantBombsTRLow,
CSDefuseBombsTRLow,
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,
CSProgressiveGameKills,
CSSelectGameKills,
CSBombGameKills,
CSGunGameKillKnifer,
CSGunGameKnifeSuicide,
CSGunGameKnifeKillKnifer,
CSGunGameSMGKillKnifer,
CSFirstBulletKills,
CSSpawnCamper,
CSBornReady,
CSKillAchievementEnd, // Must be after last kill-related achievement
// Weapon-related Achievements
CSWeaponAchievementsStart = 4000, // First weapon-related achievement
CSEnemyKillsDeagle,
CSEnemyKillsUSP,
CSEnemyKillsGlock,
CSEnemyKillsP228,
CSEnemyKillsElite,
CSEnemyKillsFiveSeven,
CSEnemyKillsBizon,
CSEnemyKillsTec9,
CSEnemyKillsTaser,
CSEnemyKillsHKP2000,
CSEnemyKillsP250,
CSEnemyKillsAWP,
CSEnemyKillsAK47,
CSEnemyKillsM4A1,
CSEnemyKillsAUG,
CSEnemyKillsSG552,
CSEnemyKillsSG550,
CSEnemyKillsGALIL,
CSEnemyKillsGALILAR,
CSEnemyKillsFAMAS,
CSEnemyKillsScout,
CSEnemyKillsG3SG1,
CSEnemyKillsSCAR17,
CSEnemyKillsSCAR20,
CSEnemyKillsSG556,
CSEnemyKillsSSG08,
CSEnemyKillsP90,
CSEnemyKillsMP5NAVY,
CSEnemyKillsTMP,
CSEnemyKillsMAC10,
CSEnemyKillsUMP45,
CSEnemyKillsMP7,
CSEnemyKillsMP9,
CSEnemyKillsM3,
CSEnemyKillsXM1014,
CSEnemyKillsMag7,
CSEnemyKillsSawedoff,
CSEnemyKillsNova,
CSEnemyKillsM249,
CSEnemyKillsNegev,
CSEnemyKillsKnife,
CSEnemyKillsHEGrenade,
CSEnemyKillsMolotov,
CSMetaPistol,
CSMetaRifle,
CSMetaSMG,
CSMetaShotgun,
CSMetaWeaponMaster,
CSWeaponAchievementsEnd, // Must be after last weapon-related achievement
// General Achievements
CSGeneralAchievementsStart = 5000, // First general achievement
CSWinRoundsLow,
CSWinRoundsMed,
CSWinRoundsHigh,
CSGGWinRoundsLow,
CSGGWinRoundsMed,
CSGGWinRoundsHigh,
CSGGWinRoundsExtreme,
CSGGWinRoundsUltimate,
CSGGRoundsLow,
CSGGRoundsMed,
CSGGRoundsHigh,
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,
#if(ALL_WEARING_SAME_UNIFORM_ACHIEVEMENT)
CSSameUniform,
#endif
CSFriendsSameUniform,
CSCauseFriendlyFireWithFlashbang,
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,
CSWinMatchDE_SHORTTRAIN,
CSWinMatchDE_LAKE,
CSWinMatchDE_SAFEHOUSE,
CSWinMatchDE_SUGARCANE,
CSWinMatchDE_STMARC,
CSWinMatchDE_BANK,
CSWinMatchDE_EMBASSY,
CSWinMatchDE_DEPOT,
CSWinMatchDE_VERTIGO,
CSWinMatchDE_BALKAN,
CSWinMatchAR_MONASTERY,
CSWinMatchAR_SHOOTS,
CSWinMatchAR_BAGGAGE,
CSWinEveryGGMap,
CSPlayEveryGGMap,
CSGunGameProgressiveRampage,
CSGunGameFirstKill,
CSKillEnemyTerrTeamBeforeBombPlant,
CSKillEnemyCTTeamBeforeBombPlant,
CSGunGameConservationist,
CSStillAlive,
CSMedalist,
CSWinMapAchievementsEnd, //Must be after last map-based achievement
CSSeason1_Start = 6200,
CSSeason1_Bronze,
CSSeason1_Silver,
CSSeason1_Gold,
CSSeason1_End // Must be after last season 1 achievement
} eCSAchievementType;
#endif // CS_ACHIEVEMENTDEFS_H
+57
View File
@@ -0,0 +1,57 @@
//========= Copyright © 1996-2005, 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 )
{
}
//-----------------------------------------------------------------------------
+54
View File
@@ -0,0 +1,54 @@
//========= Copyright © 1996-2005, 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"
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
+151
View File
@@ -0,0 +1,151 @@
//========= Copyright © 1996-2005, 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, "galilar" ) )
{
g_iAutoBuyGalilARPurchases++;
}
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++ )
{
const 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++ )
{
const CCSWeaponInfo *pWeaponInfo = GetWeaponInfo( (CSWeaponID)j );
if ( pWeaponInfo )
{
if ( pWeaponInfo->m_WeaponType != WEAPONTYPE_PISTOL )
{
iNumRifle++;
}
}
}
return iNumRifle + ARRAYSIZE( blackmarket_items );
}
#endif
+78
View File
@@ -0,0 +1,78 @@
//========= Copyright © 1996-2005, 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 );
#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
@@ -0,0 +1,212 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "networkstringtabledefs.h"
#include "gcsdk/protobufsharedobject.h"
#include "cs_econ_item_string_table.h"
#include "econ_item_view.h"
#include "econ_item_inventory.h"
#ifdef CLIENT_DLL
#include "networkstringtable_clientdll.h"
#else
#include "networkstringtable_gamedll.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#ifdef CLIENT_DLL
ConVar cs_econ_item_string_table_debug( "cs_econ_item_string_table_debug", "0", FCVAR_DEVELOPMENTONLY | FCVAR_CLIENTDLL);
#endif
CUtlMap< itemid_t, CEconItem* > g_EconItemMap( 0, 0, DefLessFunc(itemid_t) );
INetworkStringTable *g_pStringTableEconItems = NULL;
CStrikeEconItemIndex_t InvalidEconItemStringIndex()
{
return PLAYER_ECON_ITEMS_INVALID_STRING;
}
void CreateEconItemStringTable( void )
{
#ifdef CLIENT_DLL
INetworkStringTable *pNewStringTable = networkstringtable->FindTable( "EconItems" );
// This Create is called twice, once before the callbacks and once after. Only clear the map the first time so it doesn't
// get stomped.
if ( pNewStringTable != g_pStringTableEconItems )
{
g_EconItemMap.PurgeAndDeleteElements();
g_pStringTableEconItems = pNewStringTable;
g_pStringTableEconItems->SetStringChangedCallback( NULL, OnStringTableEconItemsChanged );
}
#else // GAME_DLL
g_pStringTableEconItems = networkstringtable->CreateStringTable( "EconItems", MAX_PLAYER_ECON_ITEMS_STRINGS, 0, 0, NSF_DICTIONARY_ENABLED );
#endif
}
CEconItem* GetEconItemFromStringTable( itemid_t itemID )
{
int nIndex = g_EconItemMap.Find( itemID );
if ( nIndex == g_EconItemMap.InvalidIndex() )
return NULL;
return g_EconItemMap.Element( nIndex );
}
#ifdef CLIENT_DLL
void OnStringTableEconItemsChanged( void *object, INetworkStringTable *stringTable, int stringNumber, const char *newString, void const *newData )
{
// is it new?
CStrikeEconItemIndex_t nIndex = g_EconItemMap.Find( stringNumber );
if ( nIndex == g_EconItemMap.InvalidIndex() )
{
int dataLength = 0;
const void *pEconItemData = g_pStringTableEconItems->GetStringUserData( stringNumber, &dataLength );
if ( pEconItemData )
{
CSOEconItem msgItem;
if ( !msgItem.ParseFromArray( pEconItemData, dataLength ) )
return;
CEconItem *pItem = (CEconItem *)GCSDK::CSharedObject::Create( CEconItem::k_nTypeID );
if( !pItem )
return;
pItem->DeserializeFromProtoBufItem( msgItem );
g_EconItemMap.InsertOrReplace( pItem->GetItemID(), pItem );
// Add the item to the appropriate user's inventory.
// Must be done after the econ item map is updated because this will use it.
CPlayerInventory *pLocalInventory = InventoryManager()->GetLocalInventory();
CPlayerInventory *pInventory = InventoryManager()->GetInventoryForAccount( pItem->GetAccountID() );
if ( pInventory && (pInventory != pLocalInventory) )
{
pInventory->AddEconItem( pItem, false, false, false );
}
}
}
else
{
// Add support for updating existing items.
Assert( false );
/*
// update it
CEconItemView *pItemView = g_EconItemMap.Element( nIndex );
Assert( pItemView );
if ( pItemView )
{
// todo re-init the item view
}
*/
}
}
void RepopulateInventory( CPlayerInventory *pInventory, uint32 iAccountID )
{
if ( pInventory->GetItemCount() > 0 )
return;
FOR_EACH_MAP( g_EconItemMap, i )
{
CEconItem* pItem = g_EconItemMap[i];
if ( !pItem )
continue;
if ( pItem->GetAccountID() == iAccountID )
{
pInventory->AddEconItem( pItem, false, false, false );
}
}
}
#endif // CLIENT_DLL
#ifdef GAME_DLL
CStrikeEconItemIndex_t AddEconItemToStringTable( CEconItem* pItem )
{
CStrikeEconItemIndex_t stringNumber = InvalidEconItemStringIndex();
if ( !pItem )
return stringNumber;
CSOEconItem msgItem;
pItem->SerializeToProtoBufItem( msgItem );
int entrySize = msgItem.ByteSize();
void *serializeBuffer = stackalloc( entrySize );
if ( !msgItem.SerializeWithCachedSizesToArray( ( google::protobuf::uint8 * )serializeBuffer ) )
{
Warning( "Unexpected issue serializing buff!\n" );
}
char idString[32];
Q_snprintf( idString, sizeof( idString ), "%llu", pItem->GetItemID() );
stringNumber = g_pStringTableEconItems->AddString( true, idString, entrySize, serializeBuffer );
if ( stringNumber != InvalidEconItemStringIndex() )
{
g_EconItemMap.InsertOrReplace( pItem->GetItemID(), pItem );
}
return stringNumber;
}
#endif // GAME_DLL
#ifdef GAME_DLL
CON_COMMAND_F( sv_cs_dump_econ_item_stringtable, "sv_cs_dump_econ_item_stringtable", FCVAR_NONE )
#else
CON_COMMAND_F( cl_cs_dump_econ_item_stringtable, "cl_cs_dump_econ_item_stringtable", FCVAR_NONE )
#endif
{
if ( !g_pStringTableEconItems )
{
return;
}
Msg("index,length,id,name,desc\n");
for ( int i = 0; i < g_pStringTableEconItems->GetNumStrings(); ++i )
{
int dataLength = 0;
const void *pEconItemData = g_pStringTableEconItems->GetStringUserData( i, &dataLength );
const char *pszString = g_pStringTableEconItems->GetString( i );
if ( !pEconItemData )
{
Msg( "Item Def - %s\n", pszString );
}
else
{
CSOEconItem msgItem;
if ( !msgItem.ParseFromArray( pEconItemData, dataLength ) )
{
Msg( "%d, Error parsing Econ Item!\n", i );
continue;
}
Msg("%d,%d, (%s), id:%llu\n",
i,
dataLength,
pszString,
msgItem.id()
);
Msg( "custom name: %s\n", msgItem.custom_name().c_str() );
Msg( "custom desc: %s\n", msgItem.custom_desc().c_str() );
Msg( "style: %i\n", msgItem.style() );
for ( int i=0; i<msgItem.attribute_size(); i++ )
{
Msg( "attribute %i: %i, %i\n", i, msgItem.attribute(i).def_index(), msgItem.attribute(i).value() );
}
}
}
}
@@ -0,0 +1,32 @@
#ifndef CS_ECON_ITEM_STRING_TABLE_H
#define CS_ECON_ITEM_STRING_TABLE_H
#ifdef _WIN32
#pragma once
#endif
class CPlayerInventory;
class INetworkStringTable;
typedef int CStrikeEconItemIndex_t;
// econ item string table
#define MAX_PLAYER_ECON_ITEMS_STRING_BITS 10
#define MAX_PLAYER_ECON_ITEMS_STRINGS ( 1 << MAX_PLAYER_ECON_ITEMS_STRING_BITS )
#define PLAYER_ECON_ITEMS_INVALID_STRING ( MAX_PLAYER_ECON_ITEMS_STRINGS - 1 )
#define DOTA_NETWORKED_LOADOUT_SLOT_COUNT 16
void CreateEconItemStringTable( void );
CStrikeEconItemIndex_t InvalidEconItemStringIndex();
#ifdef CLIENT_DLL
void OnStringTableEconItemsChanged( void *object, INetworkStringTable *stringTable, int stringNumber, const char *newString, void const *newData );
void RepopulateInventory( CPlayerInventory *pInventory, uint32 iAccountID );
#endif
#ifdef GAME_DLL
CStrikeEconItemIndex_t AddEconItemToStringTable( CEconItem *pItem );
#endif
CEconItem* GetEconItemFromStringTable( itemid_t itemID );
#endif //DOTA_ECON_ITEM_STRING_TABLE_H
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,496 @@
//====== Copyright © 1996-2006, Valve Corporation, All rights reserved. =======//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#ifdef GAME_DLL
#include "GameStats.h"
#endif
#include "cs_gamestats_shared.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
// note: We don't log match stats for any maps with CSSTAT_UNDEFINED for matchID
const MapName_MapStatId MapName_StatId_Table[] =
{
{"cs_assault", CSSTAT_MAP_WINS_CS_ASSAULT, CSSTAT_MAP_ROUNDS_CS_ASSAULT, CSSTAT_UNDEFINED },
{"cs_italy", CSSTAT_MAP_WINS_CS_ITALY, CSSTAT_MAP_ROUNDS_CS_ITALY, CSSTAT_UNDEFINED },
{"cs_office", CSSTAT_MAP_WINS_CS_OFFICE, CSSTAT_MAP_ROUNDS_CS_OFFICE, CSSTAT_UNDEFINED },
{"cs_militia", CSSTAT_MAP_WINS_CS_MILITIA, CSSTAT_MAP_ROUNDS_CS_MILITIA, CSSTAT_UNDEFINED },
{"de_aztec", CSSTAT_MAP_WINS_DE_AZTEC, CSSTAT_MAP_ROUNDS_DE_AZTEC, CSSTAT_UNDEFINED },
{"de_cbble", CSSTAT_MAP_WINS_DE_CBBLE, CSSTAT_MAP_ROUNDS_DE_CBBLE, CSSTAT_UNDEFINED },
{"de_dust2", CSSTAT_MAP_WINS_DE_DUST2, CSSTAT_MAP_ROUNDS_DE_DUST2, CSSTAT_UNDEFINED },
{"de_dust", CSSTAT_MAP_WINS_DE_DUST, CSSTAT_MAP_ROUNDS_DE_DUST, CSSTAT_UNDEFINED },
{"de_inferno", CSSTAT_MAP_WINS_DE_INFERNO, CSSTAT_MAP_ROUNDS_DE_INFERNO, CSSTAT_UNDEFINED },
{"de_nuke", CSSTAT_MAP_WINS_DE_NUKE, CSSTAT_MAP_ROUNDS_DE_NUKE, CSSTAT_UNDEFINED },
{"de_piranesi", CSSTAT_MAP_WINS_DE_PIRANESI, CSSTAT_MAP_ROUNDS_DE_PIRANESI, CSSTAT_UNDEFINED },
{"de_prodigy", CSSTAT_MAP_WINS_DE_PRODIGY, CSSTAT_MAP_ROUNDS_DE_PRODIGY, CSSTAT_UNDEFINED },
{"de_lake", CSSTAT_MAP_WINS_DE_LAKE, CSSTAT_MAP_ROUNDS_DE_LAKE, CSSTAT_MAP_MATCHES_WON_LAKE },
{"de_safehouse",CSSTAT_MAP_WINS_DE_SAFEHOUSE, CSSTAT_MAP_ROUNDS_DE_SAFEHOUSE, CSSTAT_MAP_MATCHES_WON_SAFEHOUSE},
{"de_shorttrain",CSSTAT_MAP_WINS_DE_SHORTTRAIN, CSSTAT_MAP_ROUNDS_DE_SHORTTRAIN, CSSTAT_MAP_MATCHES_WON_SHORTTRAIN },
{"de_sugarcane",CSSTAT_MAP_WINS_DE_SUGARCANE, CSSTAT_MAP_ROUNDS_DE_SUGARCANE, CSSTAT_MAP_MATCHES_WON_SUGARCANE },
{"de_stmarc", CSSTAT_MAP_WINS_DE_STMARC, CSSTAT_MAP_ROUNDS_DE_STMARC, CSSTAT_MAP_MATCHES_WON_STMARC },
{"de_bank", CSSTAT_MAP_WINS_DE_BANK, CSSTAT_MAP_ROUNDS_DE_BANK, CSSTAT_MAP_MATCHES_WON_BANK },
{"de_embassy", CSSTAT_MAP_WINS_DE_EMBASSY, CSSTAT_MAP_ROUNDS_DE_EMBASSY, CSSTAT_MAP_MATCHES_WON_EMBASSY },
{"de_depot", CSSTAT_MAP_WINS_DE_DEPOT, CSSTAT_MAP_ROUNDS_DE_DEPOT, CSSTAT_MAP_MATCHES_WON_DEPOT },
{"de_vertigo", CSSTAT_MAP_WINS_DE_VERTIGO, CSSTAT_MAP_ROUNDS_DE_VERTIGO, CSSTAT_UNDEFINED},
{"de_balkan", CSSTAT_MAP_WINS_DE_BALKAN, CSSTAT_MAP_ROUNDS_DE_BALKAN, CSSTAT_UNDEFINED},
{"ar_monastery",CSSTAT_MAP_WINS_AR_MONASTERY, CSSTAT_MAP_ROUNDS_AR_MONASTERY, CSSTAT_UNDEFINED},
{"ar_shoots", CSSTAT_MAP_WINS_AR_SHOOTS, CSSTAT_MAP_ROUNDS_AR_SHOOTS, CSSTAT_MAP_MATCHES_WON_SHOOTS},
{"ar_baggage", CSSTAT_MAP_WINS_AR_BAGGAGE, CSSTAT_MAP_ROUNDS_AR_BAGGAGE,CSSTAT_MAP_MATCHES_WON_BAGGAGE},
{"de_train", CSSTAT_MAP_WINS_DE_TRAIN, CSSTAT_MAP_ROUNDS_DE_TRAIN, CSSTAT_MAP_MATCHES_WON_TRAIN },
{"", CSSTAT_UNDEFINED, 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_GALILAR, CSSTAT_KILLS_GALILAR, CSSTAT_SHOTS_GALILAR, CSSTAT_HITS_GALILAR, CSSTAT_DAMAGE_GALILAR },
{ 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_GG, CSSTAT_KILLS_KNIFE, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED },
{ WEAPON_KNIFE, CSSTAT_KILLS_KNIFE, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED },
{ WEAPON_HEGRENADE, CSSTAT_KILLS_HEGRENADE, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED },
{ WEAPON_MOLOTOV, CSSTAT_KILLS_MOLOTOV, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED },
{ WEAPON_INCGRENADE, CSSTAT_KILLS_MOLOTOV, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED },
{ WEAPON_DECOY, CSSTAT_KILLS_DECOY, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED },
{ WEAPON_BIZON, CSSTAT_KILLS_BIZON, CSSTAT_SHOTS_BIZON, CSSTAT_HITS_BIZON, CSSTAT_DAMAGE_BIZON },
{ WEAPON_MAG7, CSSTAT_KILLS_MAG7, CSSTAT_SHOTS_MAG7, CSSTAT_HITS_MAG7, CSSTAT_DAMAGE_MAG7 },
{ WEAPON_NEGEV, CSSTAT_KILLS_NEGEV, CSSTAT_SHOTS_NEGEV, CSSTAT_HITS_NEGEV, CSSTAT_DAMAGE_NEGEV },
{ WEAPON_SAWEDOFF, CSSTAT_KILLS_SAWEDOFF, CSSTAT_SHOTS_SAWEDOFF, CSSTAT_HITS_SAWEDOFF, CSSTAT_DAMAGE_SAWEDOFF },
{ WEAPON_TEC9, CSSTAT_KILLS_TEC9, CSSTAT_SHOTS_TEC9, CSSTAT_HITS_TEC9, CSSTAT_DAMAGE_TEC9 },
{ WEAPON_TASER, CSSTAT_KILLS_TASER, CSSTAT_SHOTS_TASER, CSSTAT_HITS_TASER, CSSTAT_DAMAGE_TASER },
{ WEAPON_HKP2000, CSSTAT_KILLS_HKP2000, CSSTAT_SHOTS_HKP2000, CSSTAT_HITS_HKP2000, CSSTAT_DAMAGE_HKP2000 },
{ WEAPON_MP7, CSSTAT_KILLS_MP7, CSSTAT_SHOTS_MP7, CSSTAT_HITS_MP7, CSSTAT_DAMAGE_MP7 },
{ WEAPON_MP9, CSSTAT_KILLS_MP9, CSSTAT_SHOTS_MP9, CSSTAT_HITS_MP9, CSSTAT_DAMAGE_MP9 },
{ WEAPON_NOVA, CSSTAT_KILLS_NOVA, CSSTAT_SHOTS_NOVA, CSSTAT_HITS_NOVA, CSSTAT_DAMAGE_NOVA },
{ WEAPON_P250, CSSTAT_KILLS_P250, CSSTAT_SHOTS_P250, CSSTAT_HITS_P250, CSSTAT_DAMAGE_P250 },
{ WEAPON_SCAR17, CSSTAT_KILLS_SCAR17, CSSTAT_SHOTS_SCAR17, CSSTAT_HITS_SCAR17, CSSTAT_DAMAGE_SCAR17 },
{ WEAPON_SCAR20, CSSTAT_KILLS_SCAR20, CSSTAT_SHOTS_SCAR20, CSSTAT_HITS_SCAR20, CSSTAT_DAMAGE_SCAR20 },
{ WEAPON_SG556, CSSTAT_KILLS_SG556, CSSTAT_SHOTS_SG556, CSSTAT_HITS_SG556, CSSTAT_DAMAGE_SG556 },
{ WEAPON_SSG08, CSSTAT_KILLS_SSG08, CSSTAT_SHOTS_SSG08, CSSTAT_HITS_SSG08, CSSTAT_DAMAGE_SSG08 },
{ WEAPON_NONE, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED }, // This is a sentinel value so we can loop through all the stats
// { WEAPON_SENSORGRENADE, CSSTAT_KILLS_SENSOR, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED, CSSTAT_UNDEFINED },
};
struct CSStatProperty_Init
{
int statId;
CSStatProperty statProperty;
// 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
};
CSStatProperty_Init CSStatProperty_Table_Init[] =
{
// StatId Steam Name Localization Token Client Update Priority
{ CSSTAT_SHOTS_HIT, "total_shots_hit", "#GAMEUI_Stat_NumHits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_FIRED, "total_shots_fired", "#GAMEUI_Stat_NumShots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_KILLS, "total_kills", "#GAMEUI_Stat_NumKills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_DEATHS, "total_deaths", "#GAMEUI_Stat_NumDeaths", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_DAMAGE, "total_damage_done", "#GAMEUI_Stat_DamageDone", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_NUM_BOMBS_PLANTED, "total_planted_bombs", "#GAMEUI_Stat_NumPlantedBombs", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_NUM_BOMBS_DEFUSED, "total_defused_bombs", "#GAMEUI_Stat_NumDefusedBombs", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_TR_NUM_BOMBS_PLANTED, "total_TR_planted_bombs", "#GAMEUI_Stat_TR_NumPlantedBombs", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_TR_NUM_BOMBS_DEFUSED, "total_TR_defused_bombs", "#GAMEUI_Stat_TR_NumDefusedBombs", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_PLAYTIME, "total_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, "total_rounds_played", "#GAMEUI_Stat_TotalRounds", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_PISTOLROUNDS_WON, "total_wins_pistolround", "#GAMEUI_Stat_PistolRoundWins", CSSTAT_PRIORITY_ENDROUND, },
{ CSTAT_GUNGAME_ROUNDS_WON, "total_gun_game_rounds_won", "#GAMEUI_Stat_gun_game_rounds_won", CSSTAT_PRIORITY_ENDROUND, },
{ CSTAT_GUNGAME_ROUNDS_PLAYED, "total_gun_game_rounds_played", "#GAMEUI_Stat_gun_game_rounds_played", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MONEY_EARNED, "total_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_GALILAR, "total_kills_galilar", "#GAMEUI_Stat_GALILARKills", 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_KILLS_MOLOTOV, "total_kills_molotov", "#GAMEUI_Stat_MolotovKills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_DECOY, "total_kills_decoy", "#GAMEUI_Stat_DecoyKills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_BIZON, "total_kills_bizon", "#GAMEUI_Stat_BIZONKills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_MAG7, "total_kills_mag7", "#GAMEUI_Stat_MAG7Kills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_NEGEV, "total_kills_negev", "#GAMEUI_Stat_NEGEVKills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_SAWEDOFF, "total_kills_sawedoff", "#GAMEUI_Stat_SAWEDOFFKills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_TEC9, "total_kills_tec9", "#GAMEUI_Stat_TEC9Kills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_TASER, "total_kills_taser", "#GAMEUI_Stat_TASERKills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_HKP2000, "total_kills_hkp2000", "#GAMEUI_Stat_HKP2000Kills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_MP7, "total_kills_mp7", "#GAMEUI_Stat_MP7Kills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_MP9, "total_kills_mp9", "#GAMEUI_Stat_MP9Kills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_NOVA, "total_kills_nova", "#GAMEUI_Stat_NovaKills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_P250, "total_kills_p250", "#GAMEUI_Stat_P250Kills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_SCAR17, "total_kills_scar17", "#GAMEUI_Stat_SCAR17Kills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_SCAR20, "total_kills_scar20", "#GAMEUI_Stat_SCAR20Kills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_SG556, "total_kills_sg556", "#GAMEUI_Stat_SG556Kills", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_KILLS_SSG08, "total_kills_ssg08", "#GAMEUI_Stat_SSG08Kills", 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_GALILAR, "total_shots_galilar", "#GAMEUI_Stat_GALILARShots", 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_BIZON, "total_shots_bizon", "#GAMEUI_Stat_BIZONShots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_MAG7, "total_shots_mag7", "#GAMEUI_Stat_MAG7Shots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_NEGEV, "total_shots_negev", "#GAMEUI_Stat_NEGEVShots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_SAWEDOFF, "total_shots_sawedoff", "#GAMEUI_Stat_SAWEDOFFShots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_TEC9, "total_shots_tec9", "#GAMEUI_Stat_TEC9Shots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_TASER, "total_shots_taser", "#GAMEUI_Stat_TASERShots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_HKP2000, "total_shots_hkp2000", "#GAMEUI_Stat_HKP2000Shots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_MP7, "total_shots_mp7", "#GAMEUI_Stat_MP7Shots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_MP9, "total_shots_mp9", "#GAMEUI_Stat_MP9Shots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_NOVA, "total_shots_nova", "#GAMEUI_Stat_NovaShots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_P250, "total_shots_p250", "#GAMEUI_Stat_P250Shots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_SCAR17, "total_shots_scar17", "#GAMEUI_Stat_SCAR17Shots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_SCAR20, "total_shots_scar20", "#GAMEUI_Stat_SCAR20Shots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_SG556, "total_shots_sg556", "#GAMEUI_Stat_SG556Shots", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_SHOTS_SSG08, "total_shots_ssg08", "#GAMEUI_Stat_SSG08Shots", CSSTAT_PRIORITY_LOW, },
{ 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_GALILAR, "total_hits_galilar", "#GAMEUI_Stat_GALILARHits", 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_BIZON, "total_hits_bizon", "#GAMEUI_Stat_BIZONHits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_HITS_MAG7, "total_hits_mag7", "#GAMEUI_Stat_MAG7Hits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_HITS_NEGEV, "total_hits_negev", "#GAMEUI_Stat_NEGEVHits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_HITS_SAWEDOFF, "total_hits_sawedoff", "#GAMEUI_Stat_SAWEDOFFHits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_HITS_TEC9, "total_hits_tec9", "#GAMEUI_Stat_TEC9Hits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_HITS_TASER, "total_hits_taser", "#GAMEUI_Stat_TASERHits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_HITS_HKP2000, "total_hits_hkp2000", "#GAMEUI_Stat_HKP2000Hits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_HITS_MP7, "total_hits_mp7", "#GAMEUI_Stat_MP7Hits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_HITS_MP9, "total_hits_mp9", "#GAMEUI_Stat_MP9Hits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_HITS_NOVA, "total_hits_nova", "#GAMEUI_Stat_NovaHits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_HITS_P250, "total_hits_p250", "#GAMEUI_Stat_P250Hits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_HITS_SCAR17, "total_hits_scar17", "#GAMEUI_Stat_SCAR17Hits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_HITS_SCAR20, "total_hits_scar20", "#GAMEUI_Stat_SCAR20Hits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_HITS_SG556, "total_hits_sg556", "#GAMEUI_Stat_SG556Hits", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_HITS_SSG08, "total_hits_ssg08", "#GAMEUI_Stat_SSG08Hits", CSSTAT_PRIORITY_LOW, },
{ 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_GALILAR, 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_BIZON, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
{ CSSTAT_DAMAGE_MAG7, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
{ CSSTAT_DAMAGE_NEGEV, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
{ CSSTAT_DAMAGE_SAWEDOFF, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
{ CSSTAT_DAMAGE_TEC9, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
{ CSSTAT_DAMAGE_TASER, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
{ CSSTAT_DAMAGE_HKP2000, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
{ CSSTAT_DAMAGE_MP7, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
{ CSSTAT_DAMAGE_MP9, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
{ CSSTAT_DAMAGE_NOVA, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
{ CSSTAT_DAMAGE_P250, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
{ CSSTAT_DAMAGE_SCAR17, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
{ CSSTAT_DAMAGE_SCAR20, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
{ CSSTAT_DAMAGE_SG556, NULL, NULL, CSSTAT_PRIORITY_NEVER, },
{ CSSTAT_DAMAGE_SSG08, 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_KILLS_WITH_STATTRAK_WEAPON, 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_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, "total_rescued_hostages", "#GAMEUI_Stat_NumRescuedHostages", CSSTAT_PRIORITY_LOW, },
{ CSSTAT_NUM_BROKEN_WINDOWS, "total_broken_windows", "#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_CONTRIBUTION_SCORE, "total_contribution_score", "#GAMEUI_Contribution_Score", CSSTAT_PRIORITY_HIGH, },
{ CSSTAT_GG_PROGRESSIVE_CONTRIBUTION_SCORE,"total_gun_game_contribution_score", "#GAMEUI_GG_Contribution_Score", 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_MILITIA, "total_wins_map_cs_militia", "#GAMEUI_Stat_WinsMapCSMilitia", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_CS_ITALY, "total_wins_map_cs_italy", "#GAMEUI_Stat_WinsMapCSItaly", 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_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_PRODIGY, "total_wins_map_de_prodigy", "#GAMEUI_Stat_WinsMapDEProdigy", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_DE_LAKE, "total_wins_map_de_lake", "#GAMEUI_Stat_WinsMapDELake", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_DE_SAFEHOUSE, "total_wins_map_de_safehouse", "#GAMEUI_Stat_WinsMapDESafeHouse", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_DE_SHORTTRAIN, "total_wins_map_de_shorttrain", "#GAMEUI_Stat_WinsMapShorttrain", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_DE_TRAIN, "total_wins_map_de_train", "#GAMEUI_Stat_WinsMapTrain", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_DE_SUGARCANE, "total_wins_map_de_sugarcane", "#GAMEUI_Stat_WinsMapDESugarcane", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_DE_STMARC, "total_wins_map_de_stmarc", "#GAMEUI_Stat_WinsMapDEStMarc", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_DE_BANK, "total_wins_map_de_bank", "#GAMEUI_Stat_WinsMapDEBank", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_DE_EMBASSY, "total_wins_map_de_embassy", "#GAMEUI_Stat_WinsMapDEEmbassy", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_DE_DEPOT, "total_wins_map_de_depot", "#GAMEUI_Stat_WinsMapDEDepot", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_DE_VERTIGO, "total_wins_map_de_vertigo", "#GAMEUI_Stat_WinsMapDEVertigo", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_DE_BALKAN, "total_wins_map_de_balkan", "#GAMEUI_Stat_WinsMapDEBalkan", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_AR_MONASTERY, "total_wins_map_ar_monastery", "#GAMEUI_Stat_WinsMapARMonastery", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_AR_SHOOTS, "total_wins_map_ar_shoots", "#GAMEUI_Stat_WinsMapARShoots", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_WINS_AR_BAGGAGE, "total_wins_map_ar_baggage", "#GAMEUI_Stat_WinsMapARBaggage", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_CS_MILITIA, "total_rounds_map_cs_militia", "#GAMEUI_Stat_RoundsMapCSMilitia", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_CS_ASSAULT, "total_rounds_map_cs_assault", "#GAMEUI_Stat_RoundsMapCSAssault", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_CS_ITALY, "total_rounds_map_cs_italy", "#GAMEUI_Stat_RoundsMapCSItaly", 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_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_PRODIGY, "total_rounds_map_de_prodigy", "#GAMEUI_Stat_RoundsMapDEProdigy", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_DE_LAKE, "total_rounds_map_de_lake", "#GAMEUI_Stat_RoundsMapDELake", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_DE_SAFEHOUSE, "total_rounds_map_de_safehouse", "#GAMEUI_Stat_RoundsMapDESafeHouse", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_DE_SHORTTRAIN, "total_rounds_map_de_shorttrain", "#GAMEUI_Stat_RoundsMapShorttrain", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_DE_TRAIN, "total_rounds_map_de_train", "#GAMEUI_Stat_RoundsMapTrain", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_DE_SUGARCANE, "total_rounds_map_de_sugarcane", "#GAMEUI_Stat_RoundsMapDESugarcane", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_DE_STMARC, "total_rounds_map_de_stmarc", "#GAMEUI_Stat_RoundsMapDEStMarc", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_DE_BANK, "total_rounds_map_de_bank", "#GAMEUI_Stat_RoundsMapDEBank", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_DE_EMBASSY, "total_rounds_map_de_embassy", "#GAMEUI_Stat_RoundsMapDEEmbassy", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_DE_DEPOT, "total_rounds_map_de_depot", "#GAMEUI_Stat_RoundsMapDEDepot", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_DE_VERTIGO, "total_rounds_map_de_vertigo", "#GAMEUI_Stat_RoundsMapDEVertigo", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_DE_BALKAN, "total_rounds_map_de_balkan", "#GAMEUI_Stat_RoundsMapDEBalkan", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_AR_MONASTERY, "total_rounds_map_ar_monastery", "#GAMEUI_Stat_RoundsMapARMonastery", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_AR_SHOOTS, "total_rounds_map_ar_shoots", "#GAMEUI_Stat_RoundsMapARShoots", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_ROUNDS_AR_BAGGAGE, "total_rounds_map_ar_baggage", "#GAMEUI_Stat_RoundsMapAR_Baggage", CSSTAT_PRIORITY_ENDROUND, },
// match stats
{ CSSTAT_MAP_MATCHES_WON_SHOOTS, "total_matches_won_shoots", "#GAMEUI_Stat_MatchWinsShoots", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_MATCHES_WON_BAGGAGE, "total_matches_won_baggage", "#GAMEUI_Stat_MatchWinsBaggage", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_MATCHES_WON_LAKE, "total_matches_won_lake", "#GAMEUI_Stat_MatchWinsLake", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_MATCHES_WON_SUGARCANE, "total_matches_won_sugarcane", "#GAMEUI_Stat_MatchWinsSugarcane", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_MATCHES_WON_STMARC, "total_matches_won_stmarc", "#GAMEUI_Stat_MatchWinsStMarc", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_MATCHES_WON_BANK, "total_matches_won_bank", "#GAMEUI_Stat_MatchWinsBank", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_MATCHES_WON_EMBASSY, "total_matches_won_embassy", "#GAMEUI_Stat_MatchWinsEmbassy", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_MATCHES_WON_DEPOT, "total_matches_won_depot", "#GAMEUI_Stat_MatchWinsDepot", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_MATCHES_WON_SAFEHOUSE, "total_matches_won_safehouse", "#GAMEUI_Stat_MatchWinsSafeHouse", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_MATCHES_WON_SHORTTRAIN, "total_matches_won_shorttrain", "#GAMEUI_Stat_MatchWinsShorttrain", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MAP_MATCHES_WON_TRAIN, "total_matches_won_train", "#GAMEUI_Stat_MatchWinsTrain", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MATCHES_WON, "total_matches_won", "#GAMEUI_Stat_MatchWins", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MATCHES_DRAW, "total_matches_drawn", "#GAMEUI_Stat_MatchDraws", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_MATCHES_PLAYED, "total_matches_played", "#GAMEUI_Stat_MatchesPlayed", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_GUN_GAME_MATCHES_WON, "total_gg_matches_won", "#GAMEUI_Stat_MatchWinsGG", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_GUN_GAME_MATCHES_PLAYED, "total_gg_matches_played", "GAMEUI_Stat_MatchesPlayedGG", CSSTAT_PRIORITY_ENDROUND },
{ CSSTAT_GUN_GAME_PROGRESSIVE_MATCHES_WON,"total_progressive_matches_won", "#GAMEUI_Stat_MatchWinsProgressive", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_GUN_GAME_SELECT_MATCHES_WON, "total_select_matches_won", "#GAMEUI_Stat_MatchWinsSelect", CSSTAT_PRIORITY_ENDROUND, },
{ CSSTAT_GUN_GAME_TRBOMB_MATCHES_WON, "total_trbomb_matches_won", "#GAMEUI_Stat_MatchWinsTRBomb", CSSTAT_PRIORITY_ENDROUND, },
// only client tracks these
{ CSSTAT_LASTMATCH_CONTRIBUTION_SCORE, "last_match_contribution_score", "#GameUI_Stat_LastMatch_Contrib_Score", CSSTAT_PRIORITY_NEVER },
{ CSSTAT_LASTMATCH_GG_PROGRESSIVE_CONTRIBUTION_SCORE,"last_match_gg_contribution_score","#GameUI_Stat_LastMatch_gg_Contrib_Score",CSSTAT_PRIORITY_NEVER },
{ 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 },
{ CSTAT_LASTMATCH_ROUNDS_PLAYED, "last_match_rounds", "#GameUI_Stat_LastMatch_RoundsPlayed", 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
};
CSStatProperty CSStatProperty_Table[CSSTAT_MAX];
class StatPropertyTableInitializer
{
public:
StatPropertyTableInitializer()
{
memset( CSStatProperty_Table, 0, sizeof( CSStatProperty_Table ) );
for ( int i = 0; i < ARRAYSIZE( CSStatProperty_Table_Init ); ++i )
{
int statId = CSStatProperty_Table_Init[ i ].statId;
// The last entry in the table_init array is a sentinel. We were using that as
// a statId causing a 100% buffer underflow, leading to nasty problems.
if ( statId >= 0 && statId < ARRAYSIZE( CSStatProperty_Table ) )
CSStatProperty_Table[ statId ] = CSStatProperty_Table_Init[ i ].statProperty;
}
}
};
static StatPropertyTableInitializer statPropertyTableInitializer;
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];
}
}
+648
View File
@@ -0,0 +1,648 @@
//====== Copyright © 1996-2004, 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"
#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
//
// approprate 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_TR_NUM_BOMBS_PLANTED,
CSSTAT_TR_NUM_BOMBS_DEFUSED,
CSSTAT_PLAYTIME,
CSSTAT_ROUNDS_WON,
CSSTAT_T_ROUNDS_WON,
CSSTAT_CT_ROUNDS_WON,
CSSTAT_ROUNDS_PLAYED,
CSSTAT_PISTOLROUNDS_WON,
CSTAT_GUNGAME_ROUNDS_WON,
CSTAT_GUNGAME_ROUNDS_PLAYED,
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_GALILAR,
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_KILLS_MOLOTOV,
CSSTAT_KILLS_DECOY,
CSSTAT_KILLS_BIZON,
CSSTAT_KILLS_MAG7,
CSSTAT_KILLS_NEGEV,
CSSTAT_KILLS_SAWEDOFF,
CSSTAT_KILLS_TEC9,
CSSTAT_KILLS_TASER,
CSSTAT_KILLS_HKP2000,
CSSTAT_KILLS_MP7,
CSSTAT_KILLS_MP9,
CSSTAT_KILLS_NOVA,
CSSTAT_KILLS_P250,
CSSTAT_KILLS_SCAR17,
CSSTAT_KILLS_SCAR20,
CSSTAT_KILLS_SG556,
CSSTAT_KILLS_SSG08,
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_GALILAR,
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_BIZON,
CSSTAT_SHOTS_MAG7,
CSSTAT_SHOTS_NEGEV,
CSSTAT_SHOTS_SAWEDOFF,
CSSTAT_SHOTS_TEC9,
CSSTAT_SHOTS_TASER,
CSSTAT_SHOTS_HKP2000,
CSSTAT_SHOTS_MP7,
CSSTAT_SHOTS_MP9,
CSSTAT_SHOTS_NOVA,
CSSTAT_SHOTS_P250,
CSSTAT_SHOTS_SCAR17,
CSSTAT_SHOTS_SCAR20,
CSSTAT_SHOTS_SG556,
CSSTAT_SHOTS_SSG08,
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_GALILAR,
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_BIZON,
CSSTAT_HITS_MAG7,
CSSTAT_HITS_NEGEV,
CSSTAT_HITS_SAWEDOFF,
CSSTAT_HITS_TEC9,
CSSTAT_HITS_TASER,
CSSTAT_HITS_HKP2000,
CSSTAT_HITS_MP7,
CSSTAT_HITS_MP9,
CSSTAT_HITS_NOVA,
CSSTAT_HITS_P250,
CSSTAT_HITS_SCAR17,
CSSTAT_HITS_SCAR20,
CSSTAT_HITS_SG556,
CSSTAT_HITS_SSG08,
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_GALILAR,
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_BIZON,
CSSTAT_DAMAGE_MAG7,
CSSTAT_DAMAGE_NEGEV,
CSSTAT_DAMAGE_SAWEDOFF,
CSSTAT_DAMAGE_TEC9,
CSSTAT_DAMAGE_TASER,
CSSTAT_DAMAGE_HKP2000,
CSSTAT_DAMAGE_MP7,
CSSTAT_DAMAGE_MP9,
CSSTAT_DAMAGE_NOVA,
CSSTAT_DAMAGE_P250,
CSSTAT_DAMAGE_SCAR17,
CSSTAT_DAMAGE_SCAR20,
CSSTAT_DAMAGE_SG556,
CSSTAT_DAMAGE_SSG08,
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_KILLS_WITH_STATTRAK_WEAPON,
CSSTAT_DECAL_SPRAYS,
CSSTAT_TOTAL_JUMPS,
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_CONTRIBUTION_SCORE,
CSSTAT_GG_PROGRESSIVE_CONTRIBUTION_SCORE,
CSSTAT_GRENADE_DAMAGE,
CSSTAT_GRENADE_POSTHUMOUSKILLS,
CSSTAT_GRENADES_THROWN,
CSTAT_ITEMS_DROPPED_VALUE,
//Map win stats
CSSTAT_MAP_WINS_CS_MILITIA,
CSSTAT_MAP_WINS_CS_ASSAULT,
CSSTAT_MAP_WINS_CS_ITALY,
CSSTAT_MAP_WINS_CS_OFFICE,
CSSTAT_MAP_WINS_DE_AZTEC,
CSSTAT_MAP_WINS_DE_CBBLE,
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_PRODIGY,
CSSTAT_MAP_WINS_DE_LAKE,
CSSTAT_MAP_WINS_DE_SAFEHOUSE,
CSSTAT_MAP_WINS_DE_SHORTTRAIN,
CSSTAT_MAP_WINS_DE_TRAIN,
CSSTAT_MAP_WINS_DE_SUGARCANE,
CSSTAT_MAP_WINS_DE_STMARC,
CSSTAT_MAP_WINS_DE_BANK,
CSSTAT_MAP_WINS_DE_EMBASSY,
CSSTAT_MAP_WINS_DE_DEPOT,
CSSTAT_MAP_WINS_DE_VERTIGO,
CSSTAT_MAP_WINS_DE_BALKAN,
CSSTAT_MAP_WINS_AR_MONASTERY,
CSSTAT_MAP_WINS_AR_SHOOTS,
CSSTAT_MAP_WINS_AR_BAGGAGE,
CSSTAT_MAP_ROUNDS_CS_MILITIA,
CSSTAT_MAP_ROUNDS_CS_ASSAULT,
CSSTAT_MAP_ROUNDS_CS_ITALY,
CSSTAT_MAP_ROUNDS_CS_OFFICE,
CSSTAT_MAP_ROUNDS_DE_AZTEC,
CSSTAT_MAP_ROUNDS_DE_CBBLE,
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_PRODIGY,
CSSTAT_MAP_ROUNDS_DE_LAKE,
CSSTAT_MAP_ROUNDS_DE_SAFEHOUSE,
CSSTAT_MAP_ROUNDS_DE_SHORTTRAIN,
CSSTAT_MAP_ROUNDS_DE_TRAIN,
CSSTAT_MAP_ROUNDS_DE_SUGARCANE,
CSSTAT_MAP_ROUNDS_DE_STMARC,
CSSTAT_MAP_ROUNDS_DE_BANK,
CSSTAT_MAP_ROUNDS_DE_EMBASSY,
CSSTAT_MAP_ROUNDS_DE_DEPOT,
CSSTAT_MAP_ROUNDS_DE_VERTIGO,
CSSTAT_MAP_ROUNDS_DE_BALKAN,
CSSTAT_MAP_ROUNDS_AR_MONASTERY,
CSSTAT_MAP_ROUNDS_AR_SHOOTS,
CSSTAT_MAP_ROUNDS_AR_BAGGAGE,
CSSTAT_MAP_MATCHES_WON_SHOOTS,
CSSTAT_MAP_MATCHES_WON_BAGGAGE,
CSSTAT_MAP_MATCHES_WON_LAKE,
CSSTAT_MAP_MATCHES_WON_SUGARCANE,
CSSTAT_MAP_MATCHES_WON_STMARC,
CSSTAT_MAP_MATCHES_WON_BANK,
CSSTAT_MAP_MATCHES_WON_EMBASSY,
CSSTAT_MAP_MATCHES_WON_DEPOT,
CSSTAT_MAP_MATCHES_WON_SAFEHOUSE,
CSSTAT_MAP_MATCHES_WON_SHORTTRAIN,
CSSTAT_MAP_MATCHES_WON_TRAIN,
CSSTAT_MATCHES_WON,
CSSTAT_MATCHES_DRAW,
CSSTAT_MATCHES_PLAYED,
CSSTAT_GUN_GAME_MATCHES_WON,
CSSTAT_GUN_GAME_MATCHES_PLAYED,
CSSTAT_GUN_GAME_PROGRESSIVE_MATCHES_WON,
CSSTAT_GUN_GAME_SELECT_MATCHES_WON,
CSSTAT_GUN_GAME_TRBOMB_MATCHES_WON,
CSSTAT_LASTMATCH_CONTRIBUTION_SCORE,
CSSTAT_LASTMATCH_GG_PROGRESSIVE_CONTRIBUTION_SCORE,
CSSTAT_LASTMATCH_T_ROUNDS_WON,
CSSTAT_LASTMATCH_CT_ROUNDS_WON,
CSSTAT_LASTMATCH_ROUNDS_WON,
CSTAT_LASTMATCH_ROUNDS_PLAYED,
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
{
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(); }
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];
};
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++;
}
};
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
{
char* szMapName;
CSStatType_t statWinsId;
CSStatType_t statRoundsId;
CSStatType_t matchesWonId;
};
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);
#endif // CS_GAMESTATS_SHARED_H
+771
View File
@@ -0,0 +1,771 @@
//========= Copyright © 1996-2003, Valve LLC, All rights reserved. ============
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "cs_item_inventory.h"
#include "item_creation.h"
#include "vgui/ILocalize.h"
#include "tier3/tier3.h"
#ifdef CLIENT_DLL
// #include "item_pickup_panel.h"
#else
#include "cs_player.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
CCSInventoryManager g_CSInventoryManager;
CInventoryManager *InventoryManager( void )
{
return &g_CSInventoryManager;
}
CCSInventoryManager *CSInventoryManager( void )
{
return &g_CSInventoryManager;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CCSInventoryManager::CCSInventoryManager( void )
{
#ifdef CLIENT_DLL
/*
m_LocalBackpack.SetBag( BAG_BACKPACK );
for ( int i = CS_FIRST_NORMAL_CLASS; i < CS_LAST_NORMAL_CLASS; i++ )
{
m_LoadoutInventories[i].SetBag( GetLoadoutBagForClass(i) );
}
*/
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCSInventoryManager::PostInit( void )
{
BaseClass::PostInit();
GenerateBaseItems();
}
//-----------------------------------------------------------------------------
// Purpose: Generate & store the base item details for each class & loadout slot
//-----------------------------------------------------------------------------
void CCSInventoryManager::GenerateBaseItems( void )
{
/*
for ( int slot = 0; slot < LOADOUT_POSITION_COUNT; slot++ )
{
baseitemcriteria_t pCriteria;
pCriteria.iClass = 0; // FIXME[pmf]: set up CS class identifiers?
pCriteria.iSlot = slot;
int iItemDef = ItemSystem()->GenerateBaseItem( &pCriteria );
if ( iItemDef != INVALID_ITEM_INDEX )
{
/ *
IHasAttributes *pItemInterface = dynamic_cast<IHasAttributes *>(pItem);
if ( pItemInterface )
{
CScriptCreatedItem *pScriptItem = pItemInterface->GetAttributeManager()->GetItem();
Msg("============================================\n");
Msg("Inventory: Generating base item for %s, slot %s...\n", g_aPlayerClassNames_NonLocalized[iClass], g_szLoadoutStrings[slot] );
Msg("Generated: %s \"%s\"\n", g_szQualityStrings[pScriptItem->GetItemQuality()], pEnt->GetClassname() );
char tempstr[1024];
g_pVGuiLocalize->ConvertUnicodeToANSI( pScriptItem->GetAttributeDescription(), tempstr, sizeof(tempstr) );
Msg("%s", tempstr );
Msg("\n============================================\n");
}
* /
m_pBaseLoadoutItems[slot].Init( iItemDef, AE_USE_SCRIPT_VALUE, AE_USE_SCRIPT_VALUE, false );
}
else
{
m_pBaseLoadoutItems[slot].Invalidate();
}
}
*/
}
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCSInventoryManager::UpdateLocalInventory( void )
{
BaseClass::UpdateLocalInventory();
if ( steamapicontext->SteamUser() )
{
CSteamID steamID = steamapicontext->SteamUser()->GetSteamID();
/*
CSInventoryManager()->SteamRequestInventory( &m_LocalBackpack, steamID );
// Request our loadouts.
for ( int i = CS_FIRST_NORMAL_CLASS; i < CS_LAST_NORMAL_CLASS; i++ )
{
CSInventoryManager()->SteamRequestInventory( &m_LoadoutInventories[i], steamID );
}
*/
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
/*
bool CCSInventoryManager::EquipItemInLoadout( int iClass, int iSlot, globalindex_t iGlobalIndex )
{
CSteamID localSteamID = steamapicontext->SteamUser()->GetSteamID();
inventory_bags_t iLoadoutBag = GetLoadoutBagForClass( iClass );
CCSPlayerInventory *pInv = GetBagForPlayer( localSteamID, iLoadoutBag );
if ( pInv )
{
uint32 iPosition = GetBackendPositionFor(iLoadoutBag,iSlot);
if ( !iGlobalIndex )
{
CCSPlayerInventoryLoadout *pLoadoutInv = assert_cast<CCSPlayerInventoryLoadout*>( pInv );
return pLoadoutInv->ClearLoadoutSlot( iPosition );
}
return pInv->MoveItemToPosition( iGlobalIndex, iPosition );
}
return false;
}
*/
//-----------------------------------------------------------------------------
// Purpose: Fills out pList with all inventory items that could fit into the specified loadout slot for a given class
//-----------------------------------------------------------------------------
int CCSInventoryManager::GetAllUsableItemsForSlot( int iClass, int iSlot, CUtlVector<CScriptCreatedItem*> *pList )
{
// Assert( iClass >= CS_FIRST_NORMAL_CLASS && iClass < CS_CLASS_COUNT );
Assert( iSlot >= -1 && iSlot < LOADOUT_POSITION_COUNT );
int iCount = m_LocalInventory.GetItemCount();
for ( int i = 0; i < iCount; i++ )
{
CScriptCreatedItem *pItem = m_LocalInventory.GetItem(i);
CPersistentItemDefinition *pItemData = pItem->GetStaticData();
if ( !pItemData->CanBeUsedByClass(iClass) )
continue;
// Passing in iSlot of -1 finds all items usable by the class
if ( iSlot >= 0 && pItem->GetLoadoutSlot(iClass) != iSlot )
continue;
pList->AddToTail( m_LocalInventory.GetItem(i) );
}
return pList->Count();
}
#endif // CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
/*
CScriptCreatedItem *CCSInventoryManager::GetItemInLoadoutForClass( int iClass, int iSlot, CSteamID *pID )
{
#ifdef CLIENT_DLL
if ( !steamapicontext || !steamapicontext->SteamUser() )
return NULL;
CSteamID localSteamID = steamapicontext->SteamUser()->GetSteamID();
pID = &localSteamID;
#endif
inventory_bags_t iLoadoutBag = GetLoadoutBagForClass( iClass );
CCSPlayerInventory *pInv = GetBagForPlayer( *pID, iLoadoutBag );
if ( !pInv )
return NULL;
CCSPlayerInventoryLoadout *pLoadoutInv = assert_cast<CCSPlayerInventoryLoadout*>( pInv );
return pLoadoutInv->GetItemInLoadout( iSlot );
}
*/
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CCSPlayerInventory *CCSInventoryManager::GetBagForPlayer( CSteamID &playerID, inventory_bags_t iBag )
{
for ( int i = 0; i < m_pInventories.Count(); i++ )
{
if ( m_pInventories[i].pInventory->GetOwner() != playerID )
continue;
CCSPlayerInventory *pCSInv = assert_cast<CCSPlayerInventory*>( m_pInventories[i].pInventory );
if ( pCSInv->GetBag() == iBag )
return pCSInv;
}
return NULL;
}
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CCSInventoryManager::ShowItemsPickedUp( void )
{
// Go through the root inventory and find any items that are in the "found" position
CUtlVector<CScriptCreatedItem*> aItemsFound;
int iCount = m_LocalInventory.GetItemCount();
for ( int i = 0; i < iCount; i++ )
{
if ( m_LocalInventory.GetItem(i)->GetInventoryPosition() == BACKEND_POSITION_FOR_NEW_ITEM )
{
aItemsFound.AddToTail( m_LocalInventory.GetItem(i) );
m_LocalInventory.MoveItemToBackpack( m_LocalInventory.GetItem(i)->GetGlobalIndex() );
}
}
if ( !aItemsFound.Count() )
return CheckForRoomAndForceDiscard();
// We're not forcing the player to make room yet. Just show the pickup panel.
/*
CItemPickupPanel *pItemPanel = OpenItemPickupPanel();
for ( int i = 0; i < aItemsFound.Count(); i++ )
{
pItemPanel->AddItem( aItemsFound[i] );
}
*/
aItemsFound.Purge();
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CCSInventoryManager::CheckForRoomAndForceDiscard( void )
{
// Do we have room for the new item?
int iCount = m_LocalInventory.GetItemCount();
if ( iCount <= MAX_BACKPACK_SLOTS )
return false;
CScriptCreatedItem *pItem = m_LocalInventory.GetItem(MAX_BACKPACK_SLOTS);
if ( !pItem )
return false;
// We're forcing the player to make room for items he's found. Bring up that panel with the first item over the limit.
/*
CItemDiscardPanel *pDiscardPanel = OpenItemDiscardPanel();
pDiscardPanel->SetItem( pItem );
*/
return true;
}
#endif
//-----------------------------------------------------------------------------
// Purpose: Returns the item data for the base item in the loadout slot for a given class
//-----------------------------------------------------------------------------
CScriptCreatedItem *CCSInventoryManager::GetBaseItemForClass( int iSlot )
{
Assert( iSlot >= 0 && iSlot < LOADOUT_POSITION_COUNT );
return &m_pBaseLoadoutItems[iSlot];
}
//=======================================================================================================================
// CS PLAYER INVENTORY
//=======================================================================================================================
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CCSPlayerInventory::CCSPlayerInventory()
{
m_iBag = BAG_ALL_ITEMS;
}
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CCSPlayerInventory::MoveItemToPosition( globalindex_t iGlobalIndex, int iPosition )
{
CCSPlayerInventory *pRootInv = CSInventoryManager()->GetBagForPlayer( m_OwnerID, BAG_ALL_ITEMS );
if ( !pRootInv )
return false;
// Find the item in our root inventory (we don't know where it's moving from)
CScriptCreatedItem *pMovingItem = pRootInv->GetInventoryItemByGlobalIndex( iGlobalIndex );
if ( !pMovingItem )
return false;
// Is the item allowed to be in the new position?
if ( !IsItemAllowedInPosition( pMovingItem, iPosition ) )
return false;
// Get the current item in the position
CScriptCreatedItem *pItemAlreadyInPosition = GetItemByPosition(iPosition);
if ( pItemAlreadyInPosition )
{
// See if that item is allowed to be where our new item is
int iSwapPosition = pMovingItem->GetInventoryPosition();
if ( !IsItemAllowedInPosition( pItemAlreadyInPosition, iSwapPosition ) )
{
// Try to move the swapped item to the backpack, and abort if that fails
if ( !MoveItemToBackpack( pItemAlreadyInPosition->GetGlobalIndex() ) )
return false;
}
else
{
// Move the swapped item to our current position
SteamUserItems()->UpdateInventoryPos( pItemAlreadyInPosition->GetGlobalIndex(), iSwapPosition );
}
}
SteamUserItems()->UpdateInventoryPos( iGlobalIndex, iPosition );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Tries to move the specified item into the player's backpack. If this inventory isn't the
// backpack, it'll find the matching player's backpack and move it.
// FAILS if the backpack is full. Returns false in that case.
//-----------------------------------------------------------------------------
bool CCSPlayerInventory::MoveItemToBackpack( globalindex_t iGlobalIndex )
{
if ( m_iBag != BAG_BACKPACK )
{
// We're not the backpack inventory. Find it and tell it to move the item.
CCSPlayerInventory *pBackpackInv = CSInventoryManager()->GetBagForPlayer( m_OwnerID, BAG_BACKPACK );
if ( pBackpackInv )
return pBackpackInv->MoveItemToBackpack( iGlobalIndex );
}
return false;
}
#endif // CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCSPlayerInventory::InventoryReceived( EItemRequestResult eResult, int iItems )
{
BaseClass::InventoryReceived( eResult, iItems );
#ifdef CLIENT_DLL
if ( eResult == k_EItemRequestResultOK && m_iBag == BAG_ALL_ITEMS )
{
// The base bag checks for duplicate positions
int iCount = m_aInventoryItems.Count();
for ( int i = iCount-1; i >= 0; i-- )
{
uint32 iPosition = m_aInventoryItems[i].GetInventoryPosition();
// Waiting to be acknowledged?
if ( iPosition == BACKEND_POSITION_FOR_NEW_ITEM )
continue;
bool bInvalidSlot = false;
// Inside the backpack?
if ( i > 0 )
{
// We're not in an invalid slot yet. But if we're in the same position as another item, we should be moved too.
if ( iPosition == m_aInventoryItems[i-1].GetInventoryPosition() )
{
Warning("WARNING: Found item in a duplicate position. Moving to the backpack.\n" );
bInvalidSlot = true;
}
}
if ( bInvalidSlot )
{
// The item is in an invalid slot. Move it back to the backpack.
if ( !MoveItemToBackpack( m_aInventoryItems[i].GetGlobalIndex() ) )
{
// We failed to move it to the backpack, because the player has no room.
// Force them to "refind" the item, which will make them throw something out.
SteamUserItems()->UpdateInventoryPos( m_aInventoryItems[i].GetGlobalIndex(), BACKEND_POSITION_FOR_NEW_ITEM );
}
}
}
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCSPlayerInventory::DumpInventoryToConsole( bool bRoot )
{
if ( bRoot )
{
Msg("========================================\n");
#ifdef CLIENT_DLL
Msg("(CLIENT) Inventory:\n");
#else
Msg("(SERVER) Inventory for account (%d):\n", m_OwnerID.GetAccountID() );
#endif
}
Msg("Bag ID : %d\n", m_iBag );
int iCount = m_aInventoryItems.Count();
Msg(" Num items: %d\n", iCount );
for ( int i = 0; i < iCount; i++ )
{
char tempstr[1024];
g_pVGuiLocalize->ConvertUnicodeToANSI( m_aInventoryItems[i].GetItemName(), tempstr, sizeof(tempstr) );
Msg(" %s (ID %I64d) at slot %d\n", tempstr, m_aInventoryItems[i].GetGlobalIndex(), ExtractBagSlotFromBackendPosition(m_aInventoryItems[i].GetInventoryPosition()) );
}
}
//-----------------------------------------------------------------------------
// Purpose: Used to reject items on the backend for inclusion into this inventory.
// Mostly used for division of bags into different in-game inventories.
//-----------------------------------------------------------------------------
bool CCSPlayerInventory::ItemShouldBeIncluded( int iItemPosition )
{
if ( m_iBag )
{
int iItemBagPosition = ExtractBagFromBackendPosition( iItemPosition );
if ( iItemBagPosition != m_iBag )
return false;
}
return BaseClass::ItemShouldBeIncluded( iItemPosition );
}
//=======================================================================================================================
// CS PLAYER INVENTORY
//=======================================================================================================================
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if 0
CCSPlayerInventoryLoadout::CCSPlayerInventoryLoadout( void )
{
memset( m_LoadoutItems, LOADOUT_SLOT_USE_BASE_ITEM, LOADOUT_POSITION_COUNT * sizeof(int) );
}
//-----------------------------------------------------------------------------
// Purpose: Returns the item in the specified loadout slot for a given class
//-----------------------------------------------------------------------------
CScriptCreatedItem *CCSPlayerInventoryLoadout::GetItemInLoadout( int iSlot )
{
if ( iSlot < 0 || iSlot >= LOADOUT_POSITION_COUNT )
return NULL;
// If we don't have an item in the loadout at that slot, we return the base item
if ( m_LoadoutItems[iSlot] != LOADOUT_SLOT_USE_BASE_ITEM )
{
CScriptCreatedItem *pItem = GetInventoryItemByGlobalIndex( m_LoadoutItems[iSlot] );
#ifdef GAME_DLL
// To protect against users lying to the backend about the position of their items,
// we need to validate their position on the server when we retrieve them.
if ( IsItemAllowedInPosition( pItem, GetBackendPositionFor(GetBag(),iSlot) ) )
#endif
return pItem;
}
return CSInventoryManager()->GetBaseItemForClass( iSlot );
}
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CCSPlayerInventoryLoadout::MoveItemToPosition( globalindex_t iGlobalIndex, int iPosition )
{
if ( !BaseClass::MoveItemToPosition( iGlobalIndex, iPosition ) )
return false;
// TODO: Prediction
// Item has been moved, so update our loadout.
//int iSlot = ExtractBagSlotFromBackendPosition( iPosition );
//m_LoadoutItems[iSlot] = iGlobalIndex;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Removes any item in a loadout slot. If the slot hase a base item,
// the player essentially returns to using that item.
//-----------------------------------------------------------------------------
bool CCSPlayerInventoryLoadout::ClearLoadoutSlot( int iPosition )
{
CScriptCreatedItem *pItemInSlot = GetItemByPosition(iPosition);
if ( !pItemInSlot )
return false;
if ( !MoveItemToBackpack( pItemInSlot->GetGlobalIndex() ) )
return false;
/*
// TODO: Prediction
// It's been moved to the backpack, so clear out loadout entry
int iSlot = ExtractBagSlotFromBackendPosition( iPosition );
if ( iSlot >= 0 && iSlot < LOADOUT_POSITION_COUNT )
{
m_LoadoutItems[iSlot] = LOADOUT_SLOT_USE_BASE_ITEM;
}
*/
return true;
}
#endif // CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: Returns true if the specified item is allowed to be stored at the specified position
// DOES NOT check to make sure the position is clear. It's just a class / slot validity check.
//-----------------------------------------------------------------------------
bool CCSPlayerInventoryLoadout::IsItemAllowedInPosition( CScriptCreatedItem *pItem, int iPosition )
{
int iSlot = ExtractBagSlotFromBackendPosition( iPosition );
if ( pItem->GetStaticData()->m_vbClassUsability.IsBitSet( GetLoadoutClass() ) && pItem->GetLoadoutSlot() == iSlot )
return true;
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCSPlayerInventoryLoadout::InventoryReceived( EItemRequestResult eResult, int iItems )
{
if ( eResult == k_EItemRequestResultOK )
{
memset( m_LoadoutItems, LOADOUT_SLOT_USE_BASE_ITEM, LOADOUT_POSITION_COUNT * sizeof(int) );
}
#ifdef CLIENT_DLL
if ( eResult == k_EItemRequestResultOK )
{
// Now that we have all our items, validate our loadout positions.
int iCount = m_aInventoryItems.Count();
for ( int i = iCount-1; i >= 0; i-- )
{
uint32 iPosition = m_aInventoryItems[i].GetInventoryPosition();
// Waiting to be acknowledged?
if ( iPosition == BACKEND_POSITION_FOR_NEW_ITEM )
continue;
Assert( ExtractBagFromBackendPosition( iPosition ) == m_iBag );
int iBagSlot = ExtractBagSlotFromBackendPosition( iPosition );
// Ensure it's in a valid loadout slot
bool bInvalidSlot = (iBagSlot >= LOADOUT_POSITION_COUNT);
if ( !bInvalidSlot )
{
bInvalidSlot = !IsItemAllowedInPosition( &m_aInventoryItems[i], iBagSlot );
}
if ( bInvalidSlot )
{
Warning("WARNING: Found item in an invalid loadout position. Moving to the backpack.\n" );
// The item is in an invalid slot. Move it back to the backpack.
if ( !MoveItemToBackpack( m_aInventoryItems[i].GetGlobalIndex() ) )
{
// We failed to move it to the backpack, because the player has no room.
// Force them to "refind" the item, which will make them throw something out.
SteamUserItems()->UpdateInventoryPos( m_aInventoryItems[i].GetGlobalIndex(), BACKEND_POSITION_FOR_NEW_ITEM );
}
}
}
}
#endif
BaseClass::InventoryReceived( eResult, iItems );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCSPlayerInventoryLoadout::ItemHasBeenUpdated( CScriptCreatedItem *pItem )
{
// Now that we have all our items, set up out loadout pointers
uint32 iPosition = pItem->GetInventoryPosition();
int iSlot = ExtractBagSlotFromBackendPosition( iPosition );
if ( iSlot >= 0 && iSlot < LOADOUT_POSITION_COUNT )
{
Assert( GetInventoryItemByGlobalIndex(pItem->GetGlobalIndex()) );
// This may be an invalid slot for the item, but CCSPlayerInventory::InventoryReceived()
// will have detected that and sent off a request already to move it. The response
// to that will clear this loadout slot.
m_LoadoutItems[iSlot] = pItem->GetGlobalIndex();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCSPlayerInventoryLoadout::ItemIsBeingRemoved( CScriptCreatedItem *pItem )
{
// Now that we have all our items, set up out loadout pointers
uint32 iPosition = pItem->GetInventoryPosition();
int iSlot = ExtractBagSlotFromBackendPosition( iPosition );
if ( iSlot >= 0 && iSlot < LOADOUT_POSITION_COUNT )
{
m_LoadoutItems[iSlot] = LOADOUT_SLOT_USE_BASE_ITEM;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCSPlayerInventoryLoadout::DumpInventoryToConsole( bool bRoot )
{
if ( bRoot )
{
Msg("========================================\n");
#ifdef CLIENT_DLL
Msg("(CLIENT) Inventory:\n");
#else
Msg("(SERVER) Inventory for account (%d):\n", m_OwnerID.GetAccountID() );
#endif
}
Msg("Loadout for Class: %s (%d)\n", g_aPlayerClassNames_NonLocalized[GetLoadoutClass()], GetLoadoutClass() );
BaseClass::DumpInventoryToConsole( false );
if ( GetItemCount() > 0 )
{
Msg(" LOADOUT:\n");
for ( int i = 0; i < LOADOUT_POSITION_COUNT; i++ )
{
Msg(" Slot %d: ", i );
if ( m_LoadoutItems[i] != LOADOUT_SLOT_USE_BASE_ITEM )
{
CScriptCreatedItem *pItem = GetInventoryItemByGlobalIndex( m_LoadoutItems[i] );
char tempstr[1024];
g_pVGuiLocalize->ConvertUnicodeToANSI( pItem->GetItemName(), tempstr, sizeof(tempstr) );
Msg("%s (ID %I64d)\n", tempstr, pItem->GetGlobalIndex() );
}
else
{
Msg("\n");
}
}
}
}
#endif
#if 0
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CCSPlayerInventoryBackpack::CCSPlayerInventoryBackpack( void )
{
SetBag( BAG_BACKPACK );
m_iPredictedEmptySlot = 1;
}
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCSPlayerInventoryBackpack::ItemHasBeenUpdated( CScriptCreatedItem *pItem )
{
BaseClass::ItemHasBeenUpdated( pItem );
// Now that we have all our items, set up out loadout pointers
uint32 iPosition = pItem->GetInventoryPosition();
int iSlot = ExtractBagSlotFromBackendPosition( iPosition );
if ( iSlot == m_iPredictedEmptySlot )
{
CalculateNextEmptySlot();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCSPlayerInventoryBackpack::CalculateNextEmptySlot( void )
{
// Move forward looking for the first slot that doesn't have an item in it.
// We start from our current slot and only move forward, so we don't run into the problem of
// choosing a slot that's probably got another item in the process of being moved into it.
do
{
m_iPredictedEmptySlot++;
if ( !GetItemByPosition( GetBackendPositionFor(BAG_BACKPACK, m_iPredictedEmptySlot)) )
break;
} while ( m_iPredictedEmptySlot < 1000 );
}
//-----------------------------------------------------------------------------
// Purpose: Tries to move the specified item into the player's backpack.
// FAILS if the backpack is full. Returns false in that case.
//-----------------------------------------------------------------------------
bool CCSPlayerInventoryBackpack::MoveItemToBackpack( globalindex_t iGlobalIndex )
{
Warning("Moved item %I64d to backpack slot: %d\n", iGlobalIndex, m_iPredictedEmptySlot );
Assert( GetItemByPosition(GetBackendPositionFor(BAG_BACKPACK, m_iPredictedEmptySlot)) == NULL );
// Move to our current predicted empty slot, and then try to find the next slot.
SteamUserItems()->UpdateInventoryPos( iGlobalIndex, GetBackendPositionFor(BAG_BACKPACK, m_iPredictedEmptySlot) );
CalculateNextEmptySlot();
return true;
}
#endif
#ifdef CLIENT_DLL
// WTF: Declaring this inline caused a compiler bug.
CCSPlayerInventory *CCSInventoryManager::GetLocalCSInventory( void )
{
return &m_LocalInventory;
}
#endif
#ifdef _DEBUG
#if defined(CLIENT_DLL)
CON_COMMAND_F( item_dumpinv, "Dumps the contents of a specified client inventory. Format: item_dumpinv <bag index>", FCVAR_CHEAT )
#else
CON_COMMAND_F( item_dumpinv_sv, "Dumps the contents of a specified server inventory. Format: item_dumpinv_sv <bag index>", FCVAR_CHEAT )
#endif
{
int iBag = ( args.ArgC() > 1 ) ? atoi(args[1]) : BAG_ALL_ITEMS;
#if defined(CLIENT_DLL)
CSteamID steamID = steamapicontext->SteamUser()->GetSteamID();
#else
CSteamID steamID;
CCSPlayer *pPlayer = ToCSPlayer( UTIL_GetCommandClient() );
pPlayer->GetSteamID( &steamID );
#endif
CPlayerInventory *pInventory = CSInventoryManager()->GetBagForPlayer( steamID, (inventory_bags_t)iBag );
if ( !pInventory )
{
Msg("No inventory for bag %d\n", iBag);
return;
}
pInventory->DumpInventoryToConsole( true );
}
#endif
#endif
+248
View File
@@ -0,0 +1,248 @@
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose: Container that allows client & server access to data in player inventories & loadouts
//
//=============================================================================
#ifndef CS_ITEM_INVENTORY_H
#define CS_ITEM_INVENTORY_H
#ifdef _WIN32
#pragma once
#endif
#include "item_inventory.h"
#include "cs_shareddefs.h"
#define LOADOUT_SLOT_USE_BASE_ITEM 0
//===============================================================================================================
// POSITION HANDLING
//===============================================================================================================
// Items at this position have been found, but not presented to the player
#define BACKEND_POSITION_FOR_NEW_ITEM 0
// We store a bag index in the highbits of the inventory position.
// The lowbit stores the position of the item within the bag.
enum inventory_bags_t
{
BAG_ALL_ITEMS = 0,
BAG_BACKPACK = 1,
BAG_TEAM_BASE = 1000,
};
#define MAX_BACKPACK_SLOTS 50
inline uint32 GetBackendPositionFor( int iBag, int iSlot )
{
uint32 iPos = iSlot | (iBag << 16);
return iPos;
}
inline int ExtractBagFromBackendPosition( uint32 iBackendPosition )
{
int iHighbits = iBackendPosition >> 16;
return iHighbits;
}
inline int ExtractBagSlotFromBackendPosition( uint32 iBackendPosition )
{
int iLowbits = iBackendPosition & 0xFFFF;
return iLowbits;
}
/*
inline int GetClassFromLoadoutBag( int iBag )
{
return (iBag - BAG_CLASS_LOADOUT_SCOUT + 1);
}
inline inventory_bags_t GetLoadoutBagForClass( int iClass )
{
return (inventory_bags_t)(BAG_CLASS_LOADOUT_SCOUT + iClass - 1);
}
*/
//===============================================================================================================
//-----------------------------------------------------------------------------
// Purpose: A single CS player's inventory.
// On the client, the inventory manager contains contains an instance of this for the local player.
// On the server, each player contains an instance of this.
//-----------------------------------------------------------------------------
class CCSPlayerInventory : public CPlayerInventory
{
DECLARE_CLASS( CCSPlayerInventory, CPlayerInventory );
public:
CCSPlayerInventory();
void SetBag( int iBag ) { m_iBag = iBag; }
int GetBag( void ) { return m_iBag; }
// Returns true if the specified item is allowed to be stored at the specified position
// DOES NOT check to make sure the position is clear. It's just a class / slot validity check.
virtual bool IsItemAllowedInPosition( CScriptCreatedItem *pItem, int iPosition ) { return true; }
// Used to reject items on the backend for inclusion into this inventory.
// Mostly used for division of bags into different in-game inventories.
virtual bool ItemShouldBeIncluded( int iItemPosition );
protected:
// Item movement functions that are called by the inventory manager
#ifdef CLIENT_DLL
// Updates the backpack or loadout for the specified item
// Returns false if the item isn't allowed to be placed in the specified position.
virtual bool MoveItemToPosition( globalindex_t iGlobalIndex, int iPosition );
// Tries to move the specified item into the player's backpack. If this inventory isn't the
// backpack, it'll find the matching player's backpack and move it.
// FAILS if the backpack is full. Returns false in that case.
virtual bool MoveItemToBackpack( globalindex_t iGlobalIndex );
#endif
// Inventory updating, called by the Inventory Manager only. If you want an inventory updated,
// use the SteamRequestX functions in CInventoryManager.
virtual void InventoryReceived( EItemRequestResult eResult, int iItems );
// Debugging
virtual void DumpInventoryToConsole( bool bRoot );
protected:
// The bag position of this inventory, if any (0 == contains all items)
// If this inventory has a bag position, items inside other bags will be ignored.
int m_iBag;
friend class CCSInventoryManager;
// friend class CTFPlayerInventoryLoadout;
};
/*
//-----------------------------------------------------------------------------
// Purpose: Custom TF inventory that manages the player's loadout
//-----------------------------------------------------------------------------
class CTFPlayerInventoryLoadout : public CCSPlayerInventory
{
DECLARE_CLASS( CTFPlayerInventoryLoadout, CCSPlayerInventory );
public:
CTFPlayerInventoryLoadout( void );
// Returns the item in the specified loadout slot for a given class
CScriptCreatedItem *GetItemInLoadout( int iSlot );
// Get the class that this loadout inventory is for
int GetLoadoutClass( void ) { return GetClassFromLoadoutBag(m_iBag); }
// Returns true if the specified item is allowed to be stored at the specified position
// DOES NOT check to make sure the position is clear. It's just a class / slot validity check.
bool IsItemAllowedInPosition( CScriptCreatedItem *pItem, int iPosition );
// Debugging
virtual void DumpInventoryToConsole( bool bRoot );
protected:
// Item movement functions that are called by the inventory manager
#ifdef CLIENT_DLL
// Updates the backpack or loadout for the specified item
// Returns false if the item isn't allowed to be placed in the specified position.
virtual bool MoveItemToPosition( globalindex_t iGlobalIndex, int iPosition );
// Removes any item in a loadout slot. If the slot has a base item,
// the player essentially returns to using that item.
// NOTE: This can fail if the player has no backpack space to contain the equipped item.
bool ClearLoadoutSlot( int iSlot );
#endif
protected:
// Inventory updating, called by the Inventory Manager only. If you want an inventory updated,
// use the SteamRequestX functions in CInventoryManager.
virtual void InventoryReceived( EItemRequestResult eResult, int iItems );
// Derived inventory hooks
virtual void ItemHasBeenUpdated( CScriptCreatedItem *pItem );
virtual void ItemIsBeingRemoved( CScriptCreatedItem *pItem );
private:
// Global indices of the items in our inventory in the loadout slots
globalindex_t m_LoadoutItems[ LOADOUT_POSITION_COUNT ];
friend class CCSInventoryManager;
};
//-----------------------------------------------------------------------------
// Purpose: Custom TF inventory that manages the player's loadout
//-----------------------------------------------------------------------------
class CTFPlayerInventoryBackpack : public CCSPlayerInventory
{
DECLARE_CLASS( CTFPlayerInventoryBackpack, CCSPlayerInventory );
public:
CTFPlayerInventoryBackpack( void );
#ifdef CLIENT_DLL
// Tries to move the specified item into the player's backpack.
// FAILS if the backpack is full. Returns false in that case.
virtual bool MoveItemToBackpack( globalindex_t iGlobalIndex );
protected:
virtual void ItemHasBeenUpdated( CScriptCreatedItem *pItem );
void CalculateNextEmptySlot( void );
#endif
private:
int m_iPredictedEmptySlot;
};
*/
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CCSInventoryManager : public CInventoryManager
{
DECLARE_CLASS( CCSInventoryManager, CInventoryManager );
public:
CCSInventoryManager();
virtual void PostInit( void );
#ifdef CLIENT_DLL
// Show the player a pickup screen with any items they've collected recently, if any
bool ShowItemsPickedUp( void );
// Force the player to discard an item to make room for a new item, if they have one
bool CheckForRoomAndForceDiscard( void );
#endif
// Returns the item data for the base item in the loadout slot for a given class
CScriptCreatedItem *GetBaseItemForClass( int iSlot );
void GenerateBaseItems( void );
// Gets the specified inventory for the steam ID
CCSPlayerInventory *GetBagForPlayer( CSteamID &playerID, inventory_bags_t iBag );
// Returns the item in the specified loadout slot for a given class
CScriptCreatedItem *GetItemInLoadoutForClass( int iClass, int iSlot, CSteamID *pID = NULL );
private:
// Base items, returned for slots that the player doesn't have anything in
CScriptCreatedItem m_pBaseLoadoutItems[ LOADOUT_POSITION_COUNT ];
#ifdef CLIENT_DLL
// On the client, we have a single inventory for the local player. Stored here, instead of in the
// local player entity, because players need to access it while not being connected to a server.
public:
virtual void UpdateLocalInventory( void );
CPlayerInventory *GetLocalInventory( void ) { return &m_LocalInventory; }
CCSPlayerInventory *GetLocalTFInventory( void );
// Try and equip the specified item in the specified class's loadout slot
bool EquipItemInLoadout( int iClass, int iSlot, globalindex_t iGlobalIndex );
// Fills out pList with all inventory items that could fit into the specified loadout slot for a given class
int GetAllUsableItemsForSlot( int iClass, int iSlot, CUtlVector<CScriptCreatedItem*> *pList );
private:
CCSPlayerInventory m_LocalInventory;
/*
CTFPlayerInventoryBackpack m_LocalBackpack;
CTFPlayerInventoryLoadout m_LoadoutInventories[TF_CLASS_COUNT];
*/
#endif // CLIENT_DLL
};
CCSInventoryManager *CSInventoryManager( void );
#endif // CS_ITEM_INVENTORY_H
@@ -0,0 +1,39 @@
#if !defined CS_PLAYER_RANK_SHARED_H
#define CS_PLAYER_RANK_SHARED_H
enum MedalCategory_t
{
MEDAL_CATEGORY_NONE = -1,
MEDAL_CATEGORY_START = 0,
MEDAL_CATEGORY_TEAM_AND_OBJECTIVE = MEDAL_CATEGORY_START,
MEDAL_CATEGORY_COMBAT,
MEDAL_CATEGORY_WEAPON,
MEDAL_CATEGORY_MAP,
MEDAL_CATEGORY_ARSENAL,
MEDAL_CATEGORY_ACHIEVEMENTS_END,
MEDAL_CATEGORY_SEASON_COIN = MEDAL_CATEGORY_ACHIEVEMENTS_END,
MEDAL_CATEGORY_COUNT,
};
#define MEDAL_SEASON_ACCESS_OPERATION_NAME "op06"
enum MedalSeasonCoinItemIds_t
{
MEDAL_SEASON_ACCESS_ENABLED = 0,
MEDAL_SEASON_ACCESS_FREETOPLAY = 1, // 0: must own to play or must be sponsored by friend; 1: free to play with an upsell; 2: absolutely free without any notice
MEDAL_SEASON_ACCESS_VALUE = 6,
MEDAL_SEASON_COIN_BRONZE = 1336,
MEDAL_SEASON_COIN_SILVER = 1337,
MEDAL_SEASON_COIN_GOLD = 1338,
};
enum MedalRank_t
{
MEDAL_RANK_NONE,
MEDAL_RANK_BRONZE,
MEDAL_RANK_SILVER,
MEDAL_RANK_GOLD,
MEDAL_RANK_COUNT
};
#endif
File diff suppressed because it is too large Load Diff
+108
View File
@@ -0,0 +1,108 @@
#if !defined CS_PLAYER_SHARED_H
#define CS_PLAYER_SHARED_H
//
// Configuration for using high priority entities by CS players
//
class CConfigurationForHighPriorityUseEntity_t
{
public:
enum EPriority_t
{ // Priority of use entities, higher number is higher priority for use
k_EPriority_Default,
k_EPriority_Hostage,
k_EPriority_Bomb
};
enum EPlayerUseType_t
{
k_EPlayerUseType_Start, // Player wants to initiate the use
k_EPlayerUseType_Progress // Player wants to make progress using the entity
};
enum EDistanceCheckType_t
{
k_EDistanceCheckType_3D,
k_EDistanceCheckType_2D
};
CBaseEntity *m_pEntity;
EPriority_t m_ePriority;
EDistanceCheckType_t m_eDistanceCheckType;
Vector m_pos;
float m_flMaxUseDistance;
float m_flLosCheckDistance;
float m_flDotCheckAngle;
float m_flDotCheckAngleMax;
public:
// Check if this high priority use entity is better for use than the other one
bool IsBetterForUseThan( CConfigurationForHighPriorityUseEntity_t const &other ) const;
// Check if this entity can be used by the given player according to its use rules
bool UseByPlayerNow( CCSPlayer *pPlayer, EPlayerUseType_t ePlayerUseType );
};
struct HalloweenMaskModelStruct
{
char* model;
};
static const HalloweenMaskModelStruct s_HalloweenMaskModels[] =
{
{ "tf2" },
{ "models/player/holiday/facemasks/facemask_hoxton.mdl" },
{ "models/player/holiday/facemasks/porcelain_doll.mdl" },
{ "models/player/holiday/facemasks/facemask_skull.mdl" },
{ "models/player/holiday/facemasks/facemask_samurai.mdl" },
{ "models/player/holiday/facemasks/evil_clown.mdl" },
{ "tf2" },
{ "models/player/holiday/facemasks/facemask_wolf.mdl" },
{ "models/player/holiday/facemasks/facemask_sheep_model.mdl" },
{ "models/player/holiday/facemasks/facemask_bunny_gold.mdl" },
{ "models/player/holiday/facemasks/facemask_anaglyph.mdl" },
{ "models/player/holiday/facemasks/facemask_porcelain_doll_kabuki.mdl" },
{ "tf2" },
{ "models/player/holiday/facemasks/facemask_dallas.mdl" },
{ "models/player/holiday/facemasks/facemask_pumpkin.mdl" },
{ "models/player/holiday/facemasks/facemask_sheep_bloody.mdl" },
{ "models/player/holiday/facemasks/facemask_devil_plastic.mdl" },
{ "models/player/holiday/facemasks/facemask_boar.mdl" },
{ "tf2" },
{ "models/player/holiday/facemasks/facemask_chains.mdl" },
{ "models/player/holiday/facemasks/facemask_tiki.mdl" },
{ "models/player/holiday/facemasks/facemask_bunny.mdl" },
{ "models/player/holiday/facemasks/facemask_sheep_gold.mdl" },
{ "models/player/holiday/facemasks/facemask_zombie_fortune_plastic.mdl" },
{ "models/player/holiday/facemasks/facemask_chicken.mdl" },
{ "models/player/holiday/facemasks/facemask_skull_gold.mdl" },
};
static const HalloweenMaskModelStruct s_HalloweenMaskModelsCompetitive[] =
{
{ "models/player/holiday/facemasks/facemask_samurai.mdl" },
{ "models/player/holiday/facemasks/facemask_boar.mdl" },
{ "models/player/holiday/facemasks/facemask_zombie_fortune_plastic.mdl" },
{ "models/player/holiday/facemasks/facemask_porcelain_doll_kabuki.mdl" },
{ "models/player/holiday/facemasks/facemask_pumpkin.mdl" },
{ "models/player/holiday/facemasks/facemask_hoxton.mdl" },
{ "models/player/holiday/facemasks/facemask_chains.mdl" },
{ "models/player/holiday/facemasks/evil_clown.mdl" },
{ "models/player/holiday/facemasks/facemask_dallas.mdl" },
{ "models/player/holiday/facemasks/facemask_wolf.mdl" },
};
static const HalloweenMaskModelStruct s_HalloweenMaskModelsTF2[] =
{
{ "models/player/holiday/facemasks/facemask_tf2_demo_model.mdl" },
{ "models/player/holiday/facemasks/facemask_tf2_engi_model.mdl" },
{ "models/player/holiday/facemasks/facemask_tf2_heavy_model.mdl" },
{ "models/player/holiday/facemasks/facemask_tf2_medic_model.mdl" },
{ "models/player/holiday/facemasks/facemask_tf2_pyro_model.mdl" },
{ "models/player/holiday/facemasks/facemask_tf2_scout_model.mdl" },
{ "models/player/holiday/facemasks/facemask_tf2_sniper_model.mdl" },
{ "models/player/holiday/facemasks/facemask_tf2_soldier_model.mdl" },
{ "models/player/holiday/facemasks/facemask_tf2_spy_model.mdl" },
};
#endif // CS_PLAYER_SHARED_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,59 @@
//========= Copyright © 1996-2005, 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;
#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
#define HOSTAGE_JUMP_POWER 200.0f
#define HOSTAGE_ANIM_MODEL "models/hostage/hostage.mdl"
#define MOVESTATE_IDLE 0
#define MOVESTATE_WALK 1
#define MOVESTATE_RUN 2
// This abstracts the differences between CS players and hostages.
class ICSPlayerAnimStateHelpers
{
public:
virtual CWeaponCSBase* CSAnim_GetActiveWeapon() = 0;
virtual bool CSAnim_CanMove() = 0;
};
IPlayerAnimState* CreatePlayerAnimState( CBaseAnimatingOverlay *pEntity, ICSPlayerAnimStateHelpers *pHelpers, LegAnimType_t legAnimType, bool bUseAimSequences );
IPlayerAnimState* 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
+357
View File
@@ -0,0 +1,357 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "cs_shareddefs.h"
#include "gametypes/igametypes.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
const float CS_PLAYER_SPEED_RUN = 260.0f;
const float CS_PLAYER_SPEED_VIP = 227.0f;
const float CS_PLAYER_SPEED_SHIELD = 160.0f;
const float CS_PLAYER_SPEED_HAS_HOSTAGE = 200.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;
const float CS_PLAYER_HEAVYARMOR_FLINCH_MODIFIER = 0.5f;
const float CS_PLAYER_DUCK_SPEED_IDEAL = 8.0f;
const char *pszWinPanelCategoryHeaders[] =
{
"",
"#winpanel_topdamage",
"#winpanel_topheadshots",
"#winpanel_kills"
};
const char *PlayerModelInfo::g_customizationModelCT = "models/player/custom_player/scaffold_ct.mdl";
const char *PlayerModelInfo::g_customizationModelT = "models/player/custom_player/scaffold_t.mdl";
const char *PlayerModelInfo::g_defaultTModel = "tm_phoenix";
const char *PlayerModelInfo::g_defaultCTModel = "ctm_st6";
#define CFG( mdl_substr, skintone, def_glove, sleeve, override_sleeve ) { #mdl_substr, #skintone, #def_glove, #sleeve, #override_sleeve },
static PlayerViewmodelArmConfig s_playerViewmodelArmConfigs[] =
{
#include "viewmodel_arm_config.inc"
/*
// Old values, leaving for reference
// character model substr //skintone index // default glove model // associated sleeve // econ override sleeve ( if present, overrides associated sleeve if glove is econ )
{ "tm_leet", "0", "models/weapons/v_models/arms/glove_fingerless/v_glove_fingerless.mdl", "", "" },
{ "tm_phoenix", "0", "models/weapons/v_models/arms/glove_fullfinger/v_glove_fullfinger.mdl", "", "" },
{ "tm_separatist", "0", "models/weapons/v_models/arms/glove_fullfinger/v_glove_fullfinger.mdl", "models/weapons/v_models/arms/separatist/v_sleeve_separatist.mdl", "" },
{ "tm_balkan", "0", "models/weapons/v_models/arms/glove_fullfinger/v_glove_fullfinger.mdl", "models/weapons/v_models/arms/balkan/v_sleeve_balkan.mdl", "" },
{ "tm_professional_var4", "1", "models/weapons/v_models/arms/glove_fullfinger/v_glove_fullfinger.mdl", "models/weapons/v_models/arms/professional/v_sleeve_professional.mdl", "" },
{ "tm_professional", "0", "models/weapons/v_models/arms/glove_fullfinger/v_glove_fullfinger.mdl", "models/weapons/v_models/arms/professional/v_sleeve_professional.mdl", "" },
{ "tm_anarchist", "0", "models/weapons/v_models/arms/anarchist/v_glove_anarchist.mdl", "", "models/weapons/v_models/arms/anarchist/v_sleeve_anarchist.mdl" },
{ "tm_pirate", "1", "models/weapons/v_models/arms/bare/v_bare_hands.mdl", "models/weapons/v_models/arms/pirate/v_pirate_watch.mdl", "" },
{ "tm_heavy", "0", "models/weapons/v_models/arms/glove_fingerless/v_glove_fingerless.mdl", "models/weapons/v_models/arms/balkan/v_sleeve_balkan.mdl", "" },
{ "ctm_st6", "0", "models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle.mdl", "models/weapons/v_models/arms/st6/v_sleeve_st6.mdl", "" },
{ "ctm_idf", "0", "models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle.mdl", "models/weapons/v_models/arms/idf/v_sleeve_idf.mdl", "" },
{ "ctm_gign", "0", "models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle_blue.mdl", "models/weapons/v_models/arms/gign/v_sleeve_gign.mdl", "" },
{ "ctm_swat_variantb", "1", "models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle_black.mdl", "models/weapons/v_models/arms/swat/v_sleeve_swat.mdl", "" },
{ "ctm_swat", "0", "models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle_black.mdl", "models/weapons/v_models/arms/swat/v_sleeve_swat.mdl", "" },
{ "ctm_gsg9", "0", "models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle_blue.mdl", "models/weapons/v_models/arms/gsg9/v_sleeve_gsg9.mdl", "" },
{ "ctm_sas", "0", "models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle_black.mdl", "models/weapons/v_models/arms/sas/v_sleeve_sas.mdl", "" },
{ "ctm_fbi", "0", "models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle_black.mdl", "models/weapons/v_models/arms/fbi/v_sleeve_fbi.mdl", "" },
*/
};
#undef CFG
PlayerModelInfo PlayerModelInfo::s_PlayerModelInfo;
PlayerModelInfo::PlayerModelInfo()
{
#if !defined( CLIENT_DLL )
m_NumTModels = 0;
m_NumCTModels = 0;
m_NumModels = 0;
m_nNextClassT = -1;
m_nNextClassCT = -1;
m_mapName[0] = 0;
for ( int i=0; i<CS_MAX_PLAYER_MODELS; ++i )
{
m_ClassModelPaths[i][0] = 0;
m_ClassNames[i][0] = 0;
}
#endif // !CLIENT_DLL
}
const PlayerViewmodelArmConfig *GetPlayerViewmodelArmConfigForPlayerModel( const char* szPlayerModel )
{
if ( szPlayerModel != NULL )
{
for ( int i=0; i<ARRAYSIZE(s_playerViewmodelArmConfigs); i++ )
{
if ( V_stristr( szPlayerModel, s_playerViewmodelArmConfigs[i].szPlayerModelSearchSubStr ) )
return &s_playerViewmodelArmConfigs[i];
}
}
AssertMsg1( false, "Could not determine viewmodel config for character model: %s", szPlayerModel );
return &s_playerViewmodelArmConfigs[0];
}
#if !defined( CLIENT_DLL )
bool PlayerModelInfo::IsTClass( int i )
{
// The 0 model is class NONE
return (i >= GetFirstTClass() && i <= GetLastTClass() );
}
bool PlayerModelInfo::IsCTClass( int i )
{
// The 0 model is class NONE
return (i >= GetFirstCTClass() && i <= GetLastCTClass() );
}
const char *PlayerModelInfo::GetClassName( int classID )
{
AssertMsg( classID >= GetFirstClass() && classID <= GetLastClass(), "Invalid class ID for models loaded.\n ");
return m_ClassNames[classID-1];
}
const char *PlayerModelInfo::GetClassModelPath( int classID )
{
AssertMsg( classID >= GetFirstClass() && classID <= GetLastClass(), "Invalid class ID for models loaded.\n ");
return m_ClassModelPaths[classID-1];
}
int PlayerModelInfo::GetNextClassForTeam( int team )
{
if ( team == TEAM_TERRORIST )
{
if ( m_nNextClassT == -1 )
{
m_nNextClassT = RandomInt( GetFirstTClass(), GetLastTClass() );
}
++m_nNextClassT;
if ( m_nNextClassT > GetLastTClass() )
{
m_nNextClassT = GetFirstTClass();
}
return m_nNextClassT;
}
else if ( team == TEAM_CT )
{
if ( m_nNextClassCT == -1 )
{
m_nNextClassCT = RandomInt( GetFirstCTClass(), GetLastCTClass() );
}
++m_nNextClassCT;
if ( m_nNextClassCT > GetLastCTClass() )
{
m_nNextClassCT = GetFirstCTClass();
}
return m_nNextClassCT;
}
else
{
return GetFirstClass();
}
}
void PlayerModelInfo::InitializeForCurrentMap( void )
{
const char *mapName = ( gpGlobals ? STRING( gpGlobals->mapname ) : NULL );
if ( mapName &&
V_stricmp( m_mapName, mapName ) == 0 )
{
// We have already cached the model information for this map.
return;
}
if ( mapName )
{
V_strcpy( m_mapName, mapName );
}
else
{
m_mapName[0] = '\0';
}
m_NumTModels = 0;
m_NumCTModels = 0;
m_NumModels = 0;
m_nNextClassCT = -1;
m_nNextClassT = -1;
bool bUseCosmetics = false;
// If the custom character system is enabled, we should load invisible skeleton players that will be eventually clothed.
if ( bUseCosmetics )
{
//FIXME: custom characters have no audio persona; that is they don't speak yet (who would they sound like?)
AddModel( g_customizationModelT );
m_NumTModels = 1;
AddModel( g_customizationModelCT );
m_NumCTModels = 1;
DevMsg( "Using script-defined character customization definitions\n" );
}
else
{
// Add the terrorist models.
// NOTE: Terrorists must be loaded first since it is assumed they are first in the list of models.
const CUtlStringList *pTModelNames = g_pGameTypes->GetTModelsForMap( m_mapName );
if ( pTModelNames )
{
FOR_EACH_VEC( *pTModelNames, iModel )
{
const char *modelName = (*pTModelNames)[iModel];
if ( modelName )
{
AddModel( modelName );
}
}
m_NumTModels = m_NumModels;
}
// Add the default terrorist model, if no models were loaded.
if ( m_NumTModels == 0 )
{
Warning( "PlayerModelInfo: missing terrorist models for map %s. Adding the default model %s.\n", m_mapName, g_defaultTModel );
AddModel( g_defaultTModel );
m_NumTModels = 1;
}
// Add the counter-terrorist models.
const CUtlStringList *pCTModelNames = g_pGameTypes->GetCTModelsForMap( m_mapName );
if ( pCTModelNames )
{
FOR_EACH_VEC( *pCTModelNames, iModel )
{
const char *modelName = (*pCTModelNames)[iModel];
if ( modelName )
{
AddModel( modelName );
}
}
m_NumCTModels = m_NumModels - m_NumTModels;
}
// Add the default counter-terrorist model, if no models were loaded.
if ( m_NumCTModels == 0 )
{
Warning( "PlayerModelInfo: missing counter-terrorist models for map %s. Adding the default model %s.\n", m_mapName, g_defaultCTModel );
AddModel( g_defaultCTModel );
m_NumCTModels = 1;
}
}
}
void PlayerModelInfo::AddModel( const char *modelName )
{
Assert( modelName );
if ( !modelName ||
modelName[0] == '\0' )
{
return;
}
Assert( m_NumModels >= 0 && m_NumModels < CS_MAX_PLAYER_MODELS );
if ( m_NumModels >= 0 && m_NumModels < CS_MAX_PLAYER_MODELS )
{
V_strcpy_safe( m_ClassNames[m_NumModels], modelName );
if ( V_stristr( modelName, "scaffold" ) )
{
V_strcpy_safe( m_ClassModelPaths[m_NumModels], modelName );
}
else
{
char szCleanedPath[MAX_MODEL_STRING_SIZE];
V_StrSubst( m_ClassNames[m_NumModels], "models/player", "", szCleanedPath, sizeof(szCleanedPath) );
char szRedirectedPath[MAX_MODEL_STRING_SIZE];
V_sprintf_safe( szRedirectedPath, "models/player/custom_player/legacy/%s", szCleanedPath );
if ( !V_stristr( szRedirectedPath, ".mdl" ) )
V_strcat_safe( szRedirectedPath, ".mdl" );
if ( !filesystem->FileExists( szRedirectedPath, "MOD" ) )
{
AssertMsg1( false, "Verify map .kv: Player model doesn't exist: %s.", szRedirectedPath );
// Get a full path to the mdl file.
if ( !V_stristr( modelName, "models/player" ) && !V_stristr( modelName, ".mdl" ) )
{
V_snprintf( m_ClassModelPaths[m_NumModels], sizeof( m_ClassModelPaths[m_NumModels] ), "models/player/%s.mdl", modelName );
}
else
{
V_snprintf( m_ClassModelPaths[m_NumModels], sizeof( m_ClassModelPaths[m_NumModels] ), "%s", modelName );
}
}
else
{
V_strcpy_safe( m_ClassModelPaths[m_NumModels], szRedirectedPath );
}
}
++m_NumModels;
}
else
{
Warning( "PlayerModelInfo: model count has exceeded the maximum (%d) for map \"%s\". Ignoring model %s.\n",
CS_MAX_PLAYER_MODELS, m_mapName, modelName );
}
}
#endif // !CLIENT_DLL
const char* QuestProgress::ReasonString(Reason reason)
{
switch(reason)
{
case QUEST_OK:
return "ok";
case QUEST_NOT_ENOUGH_PLAYERS:
return "not_enough_players";
case QUEST_WARMUP:
return "warmup";
case QUEST_NOT_CONNECTED_TO_STEAM:
return "not_connected_to_steam";
case QUEST_NONOFFICIAL_SERVER:
return "nonofficial_server";
case QUEST_NO_ENTITLEMENT:
return "no_entitlement";
case QUEST_NO_QUEST:
return "no_quest";
case QUEST_PLAYER_IS_BOT:
return "player_is_bot";
case QUEST_WRONG_MAP:
return "wrong_map";
case QUEST_WRONG_MODE:
return "wrong_mode";
case QUEST_NOT_SYNCED_WITH_SERVER:
return "not_synced_with_server";
case QUEST_NONINITIALIZED: // treat as 'unknown reason'.
default:
return "unknown";
}
}
+474
View File
@@ -0,0 +1,474 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Shared CS definitions.
//
//=============================================================================//
#ifndef CS_SHAREDDEFS_H
#define CS_SHAREDDEFS_H
#ifdef _WIN32
#pragma once
#endif
#if !defined (_GAMECONSOLE) && !defined( GC_DLL )
#include "econ_item_view.h"
#endif
#include "csgo_limits.h"
/*======================*/
// Menu stuff //
/*======================*/
#include <game/client/iviewport.h>
#include "cs_achievementdefs.h"
// CS-specific viewport panels
#define PANEL_CHOOSE_CLASS "choose_class"
// 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 CSTRIKE_VISUALS_DATA_BYTES 96
#define MAX_HOSTAGES 12
#define MAX_HOSTAGE_RESCUES 4
#define HOSTAGE_RULE_CAN_PICKUP 1
#define MAX_MATCH_STATS_ROUNDS 30
#define MATCH_STATS_TEAM_SWAP_ROUND 15
#define IRONSIGHT // Enable viewmodel ironsight feature
#define GRENADE_UNDERHAND_FEATURE_ENABLED // Enable underhand grenade feature
#define GRENADE_DEFAULT_SIZE 2.0
// Brock H. - TR - 03/31/09
// This will allow the player to control CS bots
#define CS_CONTROLLABLE_BOTS_ENABLED 1
// demo & press build flags
#if !defined( CSTRIKE_DEMO_PRESSBUILD )
#define CSTRIKE_DEMO_PRESSBUILD 0
#endif
// Code for subscribing to SO caches for other players is disabled on the client because
// we don't use it, and the optimization to have the server send all inventory data instead
// of the gc has broken it. If we need that in the future for some reason, re-enable and figure out
// how to network (subscribing is expensive, probably should network from server like dota does).
//#define ENABLE_CLIENT_INVENTORIES_FOR_OTHER_PLAYERS
// E3
#if !defined( CSTRIKE_E3_BUILD )
#define CSTRIKE_E3_BUILD 0
#endif
//=============================================================================
#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_SHIELD;
extern const float CS_PLAYER_SPEED_STOPPED;
extern const float CS_PLAYER_SPEED_HAS_HOSTAGE;
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;
extern const float CS_PLAYER_HEAVYARMOR_FLINCH_MODIFIER;
extern const float CS_PLAYER_DUCK_SPEED_IDEAL;
#ifdef CSTRIKE15
#ifdef CLIENT_DLL
#define OLD_CROUCH_PROTOCOL_INDEX 13546
inline bool IsPreCrouchUpdateDemo( void ) { return (engine->IsHLTV() || engine->IsPlayingDemo()) && engine->GetConnectionDataProtocol() <= OLD_CROUCH_PROTOCOL_INDEX; }
#endif
#endif
template< class T >
class CUtlVectorInitialized : public CUtlVector< T >
{
public:
CUtlVectorInitialized( T* pMemory, int numElements ) : CUtlVector< T >( pMemory, numElements )
{
CUtlVector< T >::SetSize( numElements );
}
};
namespace TeamJoinFailedReason
{
enum Type
{
CHANGED_TOO_OFTEN,
BOTH_TEAMS_FULL,
TERRORISTS_FULL,
CTS_FULL,
CANT_JOIN_SPECTATOR,
HUMANS_CAN_ONLY_JOIN_TS,
HUMANS_CAN_ONLY_JOIN_CTS,
TOO_MANY_TS,
TOO_MANY_CTS,
};
};
#define CS_HOSTAGE_TRANSTIME_PICKUP 0.1
#define CS_HOSTAGE_TRANSTIME_DROP 0.25
#define CS_HOSTAGE_TRANSTIME_RESCUE 4.0
enum EHostageStates_t
{
k_EHostageStates_Idle = 0,
k_EHostageStates_BeingUntied,
k_EHostageStates_GettingPickedUp,
k_EHostageStates_BeingCarried,
k_EHostageStates_FollowingPlayer,
k_EHostageStates_GettingDropped,
k_EHostageStates_Rescued,
k_EHostageStates_Dead,
};
#define CONSTANT_UNITS_SMOKEGRENADERADIUS 166
#define CONSTANT_UNITS_GENERICGRENADERADIUS 115
const float SmokeGrenadeRadius = CONSTANT_UNITS_SMOKEGRENADERADIUS;
const float FlashbangGrenadeRadius = CONSTANT_UNITS_GENERICGRENADERADIUS;
const float HEGrenadeRadius = CONSTANT_UNITS_GENERICGRENADERADIUS;
const float MolotovGrenadeRadius = CONSTANT_UNITS_GENERICGRENADERADIUS;
const float DecoyGrenadeRadius = CONSTANT_UNITS_GENERICGRENADERADIUS;
// These go in CCSPlayer::m_iAddonBits and get sent to the client so it can create
// grenade models hanging off players.
// [mlowrance] Molotov purposely left out
#define ADDON_FLASHBANG_1 0x0001
#define ADDON_FLASHBANG_2 0x0002
#define ADDON_HE_GRENADE 0x0004
#define ADDON_SMOKE_GRENADE 0x0008
#define ADDON_C4 0x0010
#define ADDON_DEFUSEKIT 0x0020
#define ADDON_PRIMARY 0x0040
#define ADDON_PISTOL 0x0080
#define ADDON_PISTOL2 0x0100
#define ADDON_DECOY 0x0200
#define ADDON_KNIFE 0x0400
#define ADDON_MASK 0x0800
#define ADDON_TAGRENADE 0x1000
#define NUM_ADDON_BITS 13
#define ADDON_CLIENTSIDE_HOLIDAY_HAT ( 0x1 << NUM_ADDON_BITS )
#define ADDON_CLIENTSIDE_GHOST ( 0x2 << NUM_ADDON_BITS )
#define ADDON_CLIENTSIDE_ASSASSINATION_TARGET ( 0x4 << NUM_ADDON_BITS )
#define NUM_CLIENTSIDE_ADDON_BITS 3
// 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 TEAM_TERRORIST_BASE0 TEAM_TERRORIST - 2
#define TEAM_CT_BASE0 TEAM_CT - 2
// [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.5
// [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
//--------------
// CSPort Specific damage flags
//--------------
#define DMG_HEADSHOT (DMG_LASTGENERICFLAG<<1)
struct PlayerViewmodelArmConfig
{
const char *szPlayerModelSearchSubStr;
const char *szSkintoneIndex;
const char *szAssociatedGloveModel;
const char *szAssociatedSleeveModel;
const char *szAssociatedSleeveModelEconOverride;
};
// 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.
STATE_GUNGAME_RESPAWN, // Respawning the player in a gun game
STATE_DORMANT, // No thinking, client updates, etc
NUM_PLAYER_STATES
};
enum e_RoundEndReason
{
/*
NOTE/WARNING: these enum values are stored in demo files,
they are explicitly numbered for consistency and editing,
do not renumber existing elements, always add new elements
with different numeric values!
*/
Invalid_Round_End_Reason = -1,
RoundEndReason_StillInProgress = 0,
Target_Bombed = 1,
VIP_Escaped = 2,
VIP_Assassinated = 3,
Terrorists_Escaped = 4,
CTs_PreventEscape = 5,
Escaping_Terrorists_Neutralized = 6,
Bomb_Defused = 7,
CTs_Win = 8,
Terrorists_Win = 9,
Round_Draw = 10,
All_Hostages_Rescued = 11,
Target_Saved = 12,
Hostages_Not_Rescued = 13,
Terrorists_Not_Escaped = 14,
VIP_Not_Escaped = 15,
Game_Commencing = 16,
Terrorists_Surrender = 17,
CTs_Surrender = 18,
Terrorists_Planted = 19,
CTs_ReachedHostage = 20,
RoundEndReason_Count = 21,
};
enum GamePhase
{
GAMEPHASE_WARMUP_ROUND,
GAMEPHASE_PLAYING_STANDARD,
GAMEPHASE_PLAYING_FIRST_HALF,
GAMEPHASE_PLAYING_SECOND_HALF,
GAMEPHASE_HALFTIME,
GAMEPHASE_MATCH_ENDED,
GAMEPHASE_MAX
};
enum GrenadeType_t
{
GRENADE_TYPE_EXPLOSIVE,
GRENADE_TYPE_FLASH,
GRENADE_TYPE_FIRE,
GRENADE_TYPE_DECOY,
GRENADE_TYPE_SMOKE,
GRENADE_TYPE_SENSOR,
GRENADE_TYPE_TOTAL,
};
#define PUSHAWAY_THINK_INTERVAL (1.0f / 20.0f)
#define GLOWUPDATE_DEFAULT_THINK_INTERVAL 0.2f
#define CS_MAX_PLAYER_MODELS 10
#define MAX_MODEL_STRING_SIZE 256
#define CS_CLASS_NONE 0
#define MAX_ENDMATCH_VOTE_PANELS 10
const PlayerViewmodelArmConfig *GetPlayerViewmodelArmConfigForPlayerModel( const char* szPlayerModel );
class PlayerModelInfo
{
public:
PlayerModelInfo();
#if !defined( CLIENT_DLL )
bool IsTClass( int classID );
bool IsCTClass( int classID );
int GetFirstTClass( void ) const { return 1; }
int GetFirstCTClass( void ) const { return m_NumTModels + 1; }
int GetFirstClass( void ) const { return GetFirstTClass(); }
int GetLastTClass( void ) const { return m_NumTModels; }
int GetLastCTClass( void ) const { return m_NumTModels + m_NumCTModels; }
int GetLastClass( void ) const { return GetLastCTClass(); }
int GetNextClassForTeam( int team );
const char *GetClassName( int classID );
const char *GetClassModelPath( int classID );
int GetNumTModels( void ) const { return m_NumTModels; }
int GetNumCTModels( void ) const { return m_NumCTModels; }
void InitializeForCurrentMap( void );
private:
void AddModel( const char *modelName );
void SetTViewModelArms( const char *modelName );
void SetCTViewModelArms( const char *modelName );
#endif // !CLIENT_DLL
public:
static const char* g_customizationModelCT;
static const char* g_customizationModelT;
static const char *g_defaultTModel;
static const char *g_defaultCTModel;
static PlayerModelInfo* GetPtr( void ) { return &s_PlayerModelInfo; }
private:
static PlayerModelInfo s_PlayerModelInfo;
#if !defined( CLIENT_DLL )
char m_ClassModelPaths[CS_MAX_PLAYER_MODELS][MAX_MODEL_STRING_SIZE];
char m_ClassNames[CS_MAX_PLAYER_MODELS][MAX_MODEL_STRING_SIZE];
char m_mapName[MAX_MODEL_STRING_SIZE];
int m_NumTModels;
int m_NumCTModels;
int m_NumModels;
int m_nNextClassT;
int m_nNextClassCT;
#endif // !CLIENT_DLL
};
// MVP reasons
enum CSMvpReason_t
{
CSMVP_UNDEFINED = 0,
CSMVP_ELIMINATION,
CSMVP_BOMBPLANT,
CSMVP_BOMBDEFUSE,
CSMVP_HOSTAGERESCUE,
CSMVP_GUNGAMEWINNER,
};
// Keep these in sync with CSClasses.
#define CS_MUZZLEFLASH_NONE -1
#define CS_MUZZLEFLASH_NORM 0
#define CS_MUZZLEFLASH_X 1
extern const char *pszWinPanelCategoryHeaders[];
// Possible results for CSPlayer::CanAcquire
namespace AcquireResult
{
enum Type
{
Allowed,
InvalidItem,
AlreadyOwned,
AlreadyPurchased,
ReachedGrenadeTypeLimit,
ReachedGrenadeTotalLimit,
NotAllowedByTeam,
NotAllowedByMap,
NotAllowedByMode,
NotAllowedForPurchase,
NotAllowedByProhibition,
};
}
// Possible results for CSPlayer::CanAcquire
namespace AcquireMethod
{
enum Type
{
PickUp,
Buy,
};
}
// Results for CSPlayer::CanProgressQuest()
namespace QuestProgress
{
enum Reason
{
// Default value: not initialized yet (game rules or inventory data not yet retrieved)
QUEST_NONINITIALIZED,
// Quest can make progression
QUEST_OK,
// Quest can make progression if more humans connect to server
QUEST_NOT_ENOUGH_PLAYERS,
// Quest can make progression once warmup is ended.
// This is only verified on client, and could be mismatched between client and server.
QUEST_WARMUP,
// No steam account found
QUEST_NOT_CONNECTED_TO_STEAM,
// Playing on community server, quests only enabled on Valve servers
QUEST_NONOFFICIAL_SERVER,
// Don't have the challenge coin
QUEST_NO_ENTITLEMENT,
// User has no active quest
QUEST_NO_QUEST,
// User isn't human
QUEST_PLAYER_IS_BOT,
// Doesn't match state required by quest
QUEST_WRONG_MAP,
QUEST_WRONG_MODE,
// Client thinks it has quest, but the server doesn't know about it
QUEST_NOT_SYNCED_WITH_SERVER,
// Sentinel entry, never used except for maximum size verification
QUEST_REASON_MAX,
};
const int QuestReasonBits = 4;
COMPILE_TIME_ASSERT( QUEST_REASON_MAX <= ( 1 << QuestReasonBits ) );
const char* ReasonString(Reason reason); // for use by UI code, so that values stay consistent if enum changes
}
#endif // CS_SHAREDDEFS_H
+81
View File
@@ -0,0 +1,81 @@
//========= Copyright © Valve Corporation, All rights reserved. ============//
//
// Purpose: Shared code for cs teams
//
//=============================================================================//
#include "cbase.h"
#include "cs_team_shared.h"
#include "gametypes.h"
#include "cs_gamerules.h"
#if defined ( CLIENT_DLL )
#include "c_cs_team.h"
#define CCSTeam C_CSTeam
#define CBasePlayer C_BasePlayer
#else
#include "cs_team.h"
#endif
bool IsAssassinationQuest( uint32 questID )
{
CEconQuestDefinition *pQuest = GetItemSchema()->GetQuestDefinition( questID );
if ( pQuest && V_stristr( pQuest->GetQuestExpression(), "act_kill_target" ) )
return true;
return false;
}
// Checks basic conditions for a quest (mapgroup, mode, etc) to see if a quest is possible to complete
bool Helper_CheckQuestMapAndMode( const CEconQuestDefinition *pQuest )
{
const char *szMapName = NULL;
const char *szMapGroupName = NULL;
#if defined ( CLIENT_DLL )
szMapName = engine->GetLevelNameShort();
szMapGroupName = engine->GetMapGroupName();
#else
szMapName = V_UnqualifiedFileName( STRING( gpGlobals->mapname ) );
szMapGroupName = STRING( gpGlobals->mapGroupName );
#endif
// Wrong map
if ( !StringIsEmpty( pQuest->GetMap() ) && V_strcmp( szMapName, pQuest->GetMap() ) )
return false;
// Unless the map group is named after our map (so queued for a single map) also confirm we're using the right map group
if ( V_strcmp( szMapGroupName, CFmtStr( "mg_%s", szMapName ) ) )
{
if ( !StringIsEmpty( pQuest->GetMapGroup() ) && V_strcmp( szMapGroupName, pQuest->GetMapGroup() ) )
{
return false;
}
}
const char *szCurrentModeAsString = g_pGameTypes->GetGameModeFromInt( g_pGameTypes->GetCurrentGameType(), g_pGameTypes->GetCurrentGameMode() );
// Mode doesn't match
if ( V_strcmp( pQuest->GetGameMode(), szCurrentModeAsString ) )
return false;
return true;
}
bool IsAssassinationQuestActive( const CEconQuestDefinition *pQuest )
{
if ( CSGameRules() && CSGameRules()->IsWarmupPeriod() )
return false;
// We need to have an active quest with the 'act_kill_target' requirement
if ( !pQuest || !V_stristr( pQuest->GetQuestExpression(), "act_kill_target" ) )
return false;
// Validate target team
if ( pQuest->GetTargetTeam() != TEAM_TERRORIST && pQuest->GetTargetTeam() != TEAM_CT )
return false;
if ( !Helper_CheckQuestMapAndMode( pQuest ) )
return false;
return true;
}
+12
View File
@@ -0,0 +1,12 @@
//========= Copyright © Valve Corporation, All rights reserved. ============//
//
// Purpose: Shared code for cs teams
//
//=============================================================================//
#pragma once
bool IsAssassinationQuest( uint32 questID );
bool IsAssassinationQuestActive( const CEconQuestDefinition *pQuest );
@@ -0,0 +1,269 @@
//====== Copyright 1996-2004, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
//#include "stdafx.h"
#ifdef _WIN32
#include "winlite.h"
// dgoodenough- skip this on PS3 as well
// PS3_BUILDFIX
#if !defined( _X360 ) && !defined( _PS3 ) //tmauer
#include "winsock.h"
#endif
#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"
#ifdef BLACKMARKET_PRICING
#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 )
{
// dgoodenough- skip this on PS3 as well
// PS3_BUILDFIX
#if !defined( _X360 ) && !defined( _PS3 ) //tmauer
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 ;
#else
return false;
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Given a previous HTTP request parse the response into a key values buffer
//-----------------------------------------------------------------------------
bool ParseHTTPResponse( SOCKET socketHTML, uint32 *unPageHash = NULL )
{
// dgoodenough- skip this on PS3 as well
// PS3_BUILDFIX
#if !defined( _X360 ) && !defined( _PS3 ) //tmauer
char szHeaderBuf[ MED_BUFFER_SIZE ];
char szBodyBuf[ MED_BUFFER_SIZE ];
DWORD 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;
#else
return false;
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Given http url crack it into an address and the request part
//-----------------------------------------------------------------------------
bool ProcessURL( const char *pchURL, void *pSockAddrIn, char *pchRequest, int cchRequest )
{
// dgoodenough- skip this on PS3 as well
// PS3_BUILDFIX
#if !defined( _X360 ) && !defined( _PS3 ) //tmauer
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;
#else
return false;
#endif
}
//networkstringtable
bool BlackMarket_DownloadPrices( void )
{
// dgoodenough- skip this on PS3 as well
// PS3_BUILDFIX
#if !defined( _X360 ) && !defined( _PS3 ) //tmauer
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;
#else
return false;
#endif
}
#endif // BLACKMARKET_PRICING
@@ -0,0 +1,29 @@
//====== Copyright © 1996-2004, 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
File diff suppressed because it is too large Load Diff
+432
View File
@@ -0,0 +1,432 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef CS_WEAPON_PARSE_H
#define CS_WEAPON_PARSE_H
#ifdef _WIN32
#pragma once
#endif
#ifdef CLIENT_DLL
#define CWeaponCSBase C_WeaponCSBase
#endif
#include "weapon_parse.h"
#include "econ_item_constants.h"
class CWeaponCSBase;
//--------------------------------------------------------------------------------------------------------
enum CSWeaponType
{
WEAPONTYPE_KNIFE=0,
WEAPONTYPE_PISTOL,
WEAPONTYPE_SUBMACHINEGUN,
WEAPONTYPE_RIFLE,
WEAPONTYPE_SHOTGUN,
WEAPONTYPE_SNIPER_RIFLE,
WEAPONTYPE_MACHINEGUN,
WEAPONTYPE_C4,
WEAPONTYPE_GRENADE,
WEAPONTYPE_EQUIPMENT,
WEAPONTYPE_STACKABLEITEM,
WEAPONTYPE_UNKNOWN
};
/*
NOTE!!!! Please try not to change the order. If you need to add something, please add it to the end.
Anytime the order of the weaponID's change, we need to updated a bunch of tables in a couple DB's. Also,
changing the order can invalidate saved queries and in general makes using the OGS stats difficult.
*/
//--------------------------------------------------------------------------------------------------------
enum CSWeaponID
{
WEAPON_NONE = 0,
WEAPON_FIRST,
WEAPON_DEAGLE = WEAPON_FIRST,
WEAPON_ELITE,
WEAPON_FIVESEVEN,
WEAPON_GLOCK,
WEAPON_P228,
WEAPON_USP,
WEAPON_AK47,
WEAPON_AUG,
WEAPON_AWP,
WEAPON_FAMAS,
WEAPON_G3SG1,
WEAPON_GALIL,
WEAPON_GALILAR,
WEAPON_M249,
WEAPON_M3,
WEAPON_M4A1,
WEAPON_MAC10,
WEAPON_MP5NAVY,
WEAPON_P90,
WEAPON_SCOUT,
WEAPON_SG550,
WEAPON_SG552,
WEAPON_TMP,
WEAPON_UMP45,
WEAPON_XM1014,
WEAPON_BIZON,
WEAPON_MAG7,
WEAPON_NEGEV,
WEAPON_SAWEDOFF,
WEAPON_TEC9,
WEAPON_TASER,
WEAPON_HKP2000,
WEAPON_MP7,
WEAPON_MP9,
WEAPON_NOVA,
WEAPON_P250,
WEAPON_SCAR17,
WEAPON_SCAR20,
WEAPON_SG556,
WEAPON_SSG08,
WEAPON_LAST = WEAPON_SSG08,
ITEM_FIRST,
WEAPON_KNIFE_GG = ITEM_FIRST,
WEAPON_KNIFE,
WEAPON_FLASHBANG,
WEAPON_HEGRENADE,
WEAPON_SMOKEGRENADE,
WEAPON_MOLOTOV,
WEAPON_DECOY,
WEAPON_INCGRENADE,
WEAPON_TAGRENADE,
WEAPON_C4,
ITEM_MAX = WEAPON_C4,
EQUIPMENT_FIRST,
ITEM_KEVLAR = EQUIPMENT_FIRST,
ITEM_ASSAULTSUIT,
ITEM_HEAVYASSAULTSUIT,
ITEM_NVG,
ITEM_DEFUSER,
ITEM_CUTTERS,
EQUIPMENT_MAX,
WEAPON_HEALTHSHOT,
WEAPON_MAX = EQUIPMENT_MAX, // number of weapons weapon index
};
#define MAX_EQUIPMENT (EQUIPMENT_MAX - EQUIPMENT_FIRST)
enum
{
ITEM_PRICE_KEVLAR = 650,
ITEM_PRICE_HELMET = 350,
ITEM_PRICE_ASSAULTSUIT = ITEM_PRICE_KEVLAR + ITEM_PRICE_HELMET,
ITEM_PRICE_HEAVYASSAULTSUIT = 1250,
ITEM_PRICE_DEFUSEKIT = 400,
ITEM_PRICE_NVG = 1250,
};
struct WeaponPaintableMaterial_t;
void PrepareEquipmentInfo( void );
class WeaponRecoilData
{
public:
WeaponRecoilData();
~WeaponRecoilData();
void GetRecoilOffsets( CWeaponCSBase *pWeapon, int iMode, int iIndex, float& fAngle, float &fMagnitude );
void GenerateRecoilPatternForItemDefinition( item_definition_index_t idx );
private:
struct RecoilOffset
{
float fAngle;
float fMagnitude;
};
struct RecoilData
{
item_definition_index_t iItemDefIndex;
RecoilOffset recoilTable[2][64];
};
CUtlMap< item_definition_index_t, RecoilData* > m_mapRecoilTables;
void GenerateRecoilTable( RecoilData *data );
};
//--------------------------------------------------------------------------------------------------------
class CCSWeaponInfo : public FileWeaponInfo_t
{
public:
DECLARE_CLASS_GAMEROOT( CCSWeaponInfo, FileWeaponInfo_t );
CCSWeaponInfo();
virtual void Parse( ::KeyValues *pKeyValuesData, const char *szWeaponName );
// recoiltable in csweaponinfo is obsolete. remove this once confirmed that the new implementation generates the same result.
virtual void RefreshDynamicParameters() { GenerateRecoilTable(); }
const char *GetZoomInSound( void ) const { return m_szZoomINSound; }
const char *GetZoomOutSound( void ) const { return m_szZoomOUTSound; }
const Vector& GetSmokeColor() const { return m_vSmokeColor; }
// recoiltable in csweaponinfo is obsolete. remove this once confirmed that the new implementation generates the same result.
void GetRecoilOffsets( int iMode, int iIndex, float& fAngle, float &fMagnitude ) const;
protected:
CSWeaponType m_WeaponType;
int m_iTeam; // Which team can have this weapon. TEAM_UNASSIGNED if both can have it.
public:
CSWeaponID m_weaponId;
int GetWeaponPrice ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
bool IsFullAuto ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
bool HasSilencer ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetBullets ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetCycleTime ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetHeatPerShot ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetRecoveryTimeCrouch ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetRecoveryTimeStand ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetRecoveryTimeCrouchFinal ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetRecoveryTimeStandFinal ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetRecoveryTransitionStartBullet( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetRecoveryTransitionEndBullet ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetRecoilSeed ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetFlinchVelocityModifierLarge ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetFlinchVelocityModifierSmall ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetTimeToIdleAfterFire ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetIdleInterval ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetRange ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetRangeModifier ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetDamage ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetPenetration ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetCrosshairDeltaDistance ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetCrosshairMinDistance ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetInaccuracyAltSwitch ( void ) const { return m_fInaccuracyAltSwitch; };
float GetInaccuracyPitchShift ( void ) const { return m_fInaccuracyPitchShift; }
float GetInaccuracyAltSoundThreshhold ( void ) const { return m_fInaccuracyAltSoundThreshold; }
float GetMaxSpeed ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetSpread ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f ) const;
float GetInaccuracyCrouch ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f ) const;
float GetInaccuracyStand ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f ) const;
float GetInaccuracyJumpInitial ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f ) const;
float GetInaccuracyJump ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f ) const;
float GetInaccuracyLand ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f ) const;
float GetInaccuracyLadder ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f ) const;
float GetInaccuracyFire ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f ) const;
float GetInaccuracyMove ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f ) const;
float GetInaccuracyReload ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 0.001f ) const;
float GetRecoilAngle ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetRecoilAngleVariance ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetRecoilMagnitude ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetRecoilMagnitudeVariance ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetTracerFrequency ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetPrimaryClipSize ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetSecondaryClipSize ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetDefaultPrimaryClipSize ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetDefaultSecondaryClipSize ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetKillAward ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
bool HasBurstMode ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
bool IsRevolver ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
bool HasAlternateFastSlowReload ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetArmorRatio ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
bool HasTraditionalScope ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
bool CannotShootUnderwater ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
bool DoesUnzoomAfterShot ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
bool DoesHideViewModelWhenZoomed ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetBucketSlot ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetZoomLevels ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetZoomFOV1 ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetZoomFOV2 ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetZoomTime0 ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetZoomTime1 ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
float GetZoomTime2 ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetPrimaryReserveAmmoMax ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
int GetSecondaryReserveAmmoMax ( const CEconItemView* pWepView = NULL, int nAlt = 0, float flScale = 1.0f ) const;
CSWeaponType GetWeaponType ( const CEconItemView* pWepView = NULL ) const;
const char* GetAddonLocation ( const CEconItemView* pWepView = NULL ) const;
const char* GetEjectBrassEffectName ( const CEconItemView* pWepView = NULL ) const;
const char* GetTracerEffectName ( const CEconItemView* pWepView = NULL ) const;
const char* GetMuzzleFlashEffectName_1stPerson ( const CEconItemView* pWepView = NULL ) const;
const char* GetMuzzleFlashEffectName_1stPersonAlt ( const CEconItemView* pWepView = NULL ) const;
const char* GetMuzzleFlashEffectName_3rdPerson ( const CEconItemView* pWepView = NULL ) const;
const char* GetMuzzleFlashEffectName_3rdPersonAlt ( const CEconItemView* pWepView = NULL ) const;
const char* GetHeatEffectName ( const CEconItemView* pWepView = NULL ) const;
const char* GetPlayerAnimationExtension ( const CEconItemView* pWepView = NULL ) const;
void SetUsedByTeam ( int nTeam ) { m_iTeam = nTeam; }
int GetUsedByTeam ( const CEconItemView* pWepView = NULL ) const;
bool CanBeUsedWithShield() const { return m_bCanUseWithShield; }
float GetBotAudibleRange() const { return m_flBotAudibleRange; }
const char* GetWrongTeamMsg() const { return m_WrongTeamMsg; }
const char* GetAnimExtension() const { return m_szAnimExtension; }
const char* GetShieldViewModel() const { return m_szShieldViewModel; }
const char* GetSilencerModel() const { return m_szSilencerModel; }
float GetAddonScale() const { return m_flAddonScale; }
float GetThrowVelocity() const { return m_fThrowVelocity; }
const char* GetAddonModel ( const CEconItemView* pWepView = NULL ) const;
const CUtlVector< WeaponPaintableMaterial_t >* GetPaintData( const CEconItemView* pWepView = NULL ) const;
// recoiltable in csweaponinfo is obsolete. remove this once confirmed that the new implementation generates the same result.
void GenerateRecoilTable();
void SetWeaponPrice( int price ) { m_iWeaponPrice = price; };
void SetWeaponType( CSWeaponType type ) { m_WeaponType = type; };
private:
static bool m_bCSWeaponInfoLookupInitialized;
bool m_bFullAuto; // is this a fully automatic weapon?
float m_flHeatPerShot;
int m_iWeaponPrice;
float m_flArmorRatio;
float m_flMaxSpeed[2]; // How fast the player can run while this is his primary weapon.
int m_iCrosshairMinDistance;
int m_iCrosshairDeltaDistance;
// Parameters for FX_FireBullets:
float m_flPenetration;
int m_iDamage;
float m_flRange;
float m_flRangeModifier;
int m_iBullets;
float m_flCycleTime;
float m_flCycleTimeAlt;
char m_szHeatEffectName[MAX_WEAPON_STRING];
Vector m_vSmokeColor;
char m_szMuzzleFlashEffectName_1stPerson[MAX_WEAPON_STRING];
char m_szMuzzleFlashEffectName_3rdPerson[MAX_WEAPON_STRING];
char m_szEjectBrassEffectName[MAX_WEAPON_STRING];
char m_szTracerEffectName[MAX_WEAPON_STRING];
int m_iTracerFequency;
// 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_fRecoveryTimeStandFinal;
float m_fRecoveryTimeCrouchFinal;
float m_fInaccuracyReload;
float m_fInaccuracyAltSwitch;
float m_fInaccuracyPitchShift;
float m_fInaccuracyAltSoundThreshold;
float m_fRecoilAngle[2];
float m_fRecoilAngleVariance[2];
float m_fRecoilMagnitude[2];
float m_fRecoilMagnitudeVariance[2];
int m_iRecoilSeed;
float m_fFlinchVelocityModifierLarge; // velocity modifier for anyone hit by this weapon
float m_fFlinchVelocityModifierSmall; // velocity modifier for anyone hit by this weapon
// Delay until the next idle animation after shooting.
float m_flTimeToIdleAfterFire;
float m_flIdleInterval;
// recoiltable in csweaponinfo is obsolete. remove this once confirmed that the new implementation generates the same result.
struct RecoilOffset
{
float fAngle;
float fMagnitude;
};
RecoilOffset m_recoilTable[2][64];
int m_iZoomLevels;
int m_iZoomFov[ 3 ];
float m_fZoomTime[ 3 ];
bool m_bHideViewModelZoomed;
char m_szZoomINSound[ MAX_WEAPON_STRING ];
char m_szZoomOUTSound[ MAX_WEAPON_STRING ];
float m_flBotAudibleRange; // How far away a bot can hear this weapon.
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_szAddonLocation[ MAX_WEAPON_STRING ]; //If this is set, the weapon will look for an attachment location with this name. Otherwize the default is used based on weapon type.
char m_szSilencerModel[ MAX_WEAPON_STRING ]; // Alternate model with silencer attached
float m_flAddonScale;
// grenade throw parameters
float m_fThrowVelocity;
int m_iKillAward;
};
//--------------------------------------------------------------------------------------------------------
// Utility conversion functions
//--------------------------------------------------------------------------------------------------------
const char* WeaponClassAsString( CSWeaponType weaponType );
CSWeaponType WeaponClassFromString( const char * weaponType );
CSWeaponType WeaponClassFromWeaponID( CSWeaponID weaponID );
const char* WeaponIdAsString( CSWeaponID weaponID );
CSWeaponID WeaponIdFromString( const char *szWeaponName );
const char *WeaponIDToAlias( int id );
CSWeaponID AliasToWeaponID( const char *szAlias );
const CCSWeaponInfo* GetWeaponInfo( CSWeaponID weaponID );
bool IsGunWeapon( CSWeaponType weaponType );
#endif // CS_WEAPON_PARSE_H
@@ -0,0 +1,454 @@
//====== Copyright Valve Corporation, All rights reserved. =================
//
//=============================================================================
#include "cbase.h"
#include "cs_workshop_manager.h"
#include "tier2/fileutils.h"
#if !defined ( _GAMECONSOLE ) && !defined ( NO_STEAM )
#define COMMUNITY_MAP_PATH "maps/workshop" // Path to Workshop maps downloaded from Steam
#define COMMUNITY_MAP_THUMBNAIL_PREFIX "thumb" // Prefix for thumbnail filename
extern ConVar cl_debug_ugc_downloads;
CSGOWorkshopMaps g_CSGOWorkshopMaps;
CWorkshopManager g_WorkshopManager( &g_CSGOWorkshopMaps );
CWorkshopManager &WorkshopManager( void )
{
return g_WorkshopManager;
}
CON_COMMAND( cl_remove_all_workshop_maps, "Removes all maps from the workshop directory." )
{
CUtlVector<CUtlString> outList;
RecursiveFindFilesMatchingName( &outList, "maps/workshop", "*.*", "GAME" );
FOR_EACH_VEC( outList, i )
{
CUtlString &curMap = outList[i];
// skip '.' and '..' results
if ( curMap.Length() > 0 && curMap.Access()[curMap.Length()-1] == '.' )
continue;
PublishedFileId_t id = GetMapIDFromMapPath( curMap.Access() );
if ( id != 0 )
{
filesystem->RemoveFile( outList[i] );
}
}
}
CSGOWorkshopMaps::CSGOWorkshopMaps()
{
m_bUGCRequestsPaused = false;
m_bEnumerateMapsFailed = false;
}
bool CSGOWorkshopMaps::Init( void )
{
UGCUtil_Init();
QueryForCommunityMaps();
return true;
}
void CSGOWorkshopMaps::Shutdown( void )
{
UGCUtil_Shutdown();
}
void CSGOWorkshopMaps::Update( float frametime )
{
UpdateWorkshopRequests();
}
//-----------------------------------------------------------------------------
// Purpose: Update all our Workshop work
//-----------------------------------------------------------------------------
void CSGOWorkshopMaps::UpdateWorkshopRequests( void )
{
// Update our file upload/download requests from Steam
WorkshopManager().Update();
}
//-----------------------------------------------------------------------------
// Purpose: Request all subscribed files for a user
//-----------------------------------------------------------------------------
void CSGOWorkshopMaps::QueryForCommunityMaps( void )
{
Log_Msg( LOG_WORKSHOP, "[CSGOWorkshopMaps] Querying for subscribed files\n" );
//AddCommunityMap( 2747, 0 );
// Start our call for subscribed maps
if ( ISteamRemoteStorage *pRemoteStorage = GetISteamRemoteStorage() )
{
m_flQueueBaselineRequestTime = gpGlobals->curtime;
// FIXME: JDW - Remove to test timeout
// return;
int nStartIndex = ( m_nTotalSubscriptionsLoaded > 0 ) ? (m_nTotalSubscriptionsLoaded-1) : 0;
SteamAPICall_t hSteamAPICall = pRemoteStorage->EnumerateUserSubscribedFiles( nStartIndex );
m_callbackEnumerateSubscribedMaps.Set( hSteamAPICall, this, &CSGOWorkshopMaps::Steam_OnEnumerateSubscribedMaps );
}
}
//-----------------------------------------------------------------------------
// Purpose: Callback for completion of enumerating the subscribed maps for the user
//-----------------------------------------------------------------------------
void CSGOWorkshopMaps::Steam_OnEnumerateSubscribedMaps( RemoteStorageEnumerateUserSubscribedFilesResult_t *pResult, bool bError )
{
// Make sure we succeeded
if ( bError || pResult->m_eResult != k_EResultOK )
{
Warning( "Unable to enumerate user's subscribed maps!\n" );
m_bEnumerateMapsFailed = true;
return;
}
m_bEnumerateMapsFailed = false;
// Queue up all the known subscribed files to work through over subsequent frames
const int nNumMaps = pResult->m_nResultsReturned;
for ( int i = 0; i < nNumMaps; i++ )
{
AddCommunityMap( pResult->m_rgPublishedFileId[i], pResult->m_rgRTimeSubscribed[i] );
}
m_nTotalSubscriptionsLoaded += nNumMaps;
m_bReceivedQueueBaseline = true;
// If our queue is bigger than this call could return in one go, call again to receive more
if ( m_nTotalSubscriptionsLoaded < pResult->m_nTotalResultCount )
{
QueryForCommunityMaps();
}
}
//-----------------------------------------------------------------------------
// Purpose: Add a new map into the system
//-----------------------------------------------------------------------------
void CSGOWorkshopMaps::AddCommunityMap( PublishedFileId_t nMapID, uint32 nSubscribeTime )
{
// Queue up a new request for this file's history
CCommunityMapRequest *pMapRequest = new CCommunityMapRequest( nMapID, nSubscribeTime );
WorkshopManager().AddFileInfoQuery( pMapRequest, true );
// Add this into our list of history items for this user
if ( m_vecCommunityMapsQueue.Find( nMapID ) == m_vecCommunityMapsQueue.InvalidIndex() )
{
m_vecCommunityMapsQueue.AddToTail( nMapID );
}
}
//-----------------------------------------------------------------------------
// Purpose: Requests voting information for a published file
// Return: If true, the voting data already exists and can be immediately accessed. Otherwise, the caller will need to wait
//-----------------------------------------------------------------------------
bool CSGOWorkshopMaps::AddPublishedFileVoteInfoRequest( const PublishedFileInfo_t *pInfo, bool bForceUpdate /*=false*/ )
{
return WorkshopManager().AddPublishedFileVoteInfoRequest( pInfo, bForceUpdate );
}
//-----------------------------------------------------------------------------
// Purpose: Tell the GC to unsubscribe from this map
//-----------------------------------------------------------------------------
bool CSGOWorkshopMaps::UnsubscribeFromMap( PublishedFileId_t nMapID )
{
if ( steamapicontext == NULL || steamapicontext->SteamRemoteStorage() == NULL )
return false;
if ( steamapicontext->SteamRemoteStorage()->UnsubscribePublishedFile( nMapID ) == k_uAPICallInvalid )
{
//TODO: Handle the error case
Log_Warning( LOG_WORKSHOP, "[BaseModPanel] Failed to unsubscribe from published file: %llu\n", nMapID );
return false;
}
Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Unsubscribing from published file: %llu\n", nMapID );
// NOTE: We listen for unsubscription notifications already, so we'll pick up that case down the road
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Delete a file request from the system (optionally removing its downloaded content form the disk)
//-----------------------------------------------------------------------------
bool CSGOWorkshopMaps::RemoveCommunityMap( PublishedFileId_t nID )
{
/*
// FIXME: Grr, we need to handle the current query being the one we're trying to nuke!
if ( m_nFilesToQuery.Count() && m_nFilesToQuery.Head() == nID )
{
Assert(0);
}
*/
// Remove this from our queue, but leave the file information intact
if ( m_vecCommunityMapsQueue.FindAndFastRemove( nID ) )
{
// Notify the dialog that something has changed underneath it and it needs to refresh
// UNDONE --
return true;
}
return false;
}
void CSGOWorkshopMaps::OnFileRequestFinished( UGCHandle_t hFileHandle )
{
}
void CSGOWorkshopMaps::OnFileRequestError( UGCHandle_t hFileHandle )
{
}
void CSGOWorkshopMaps::OnPublishedFileSubscribed( PublishedFileId_t nID )
{
/** Removed for partner depot **/
}
void CSGOWorkshopMaps::OnPublishedFileUnsubscribed( PublishedFileId_t nID )
{
RemoveCommunityMap( nID );
IGameEvent* pEvent = gameeventmanager->CreateEvent( "ugc_map_unsubscribed" );
if ( pEvent )
{
pEvent->SetUint64( "published_file_id", nID );
gameeventmanager->FireEventClientSide( pEvent );
}
}
void CSGOWorkshopMaps::OnPublishedFileDeleted( PublishedFileId_t nID )
{
}
bool CSGOWorkshopMaps::IsSubscribedMap( const char *pchMapName, bool bOnlyOnDisk )
{
for ( int i = 0; i < m_vecCommunityMapsQueue.Count(); ++i )
{
const PublishedFileInfo_t *pFileInfo = WorkshopManager().GetPublishedFileInfoByID( m_vecCommunityMapsQueue[ i ] );
if ( pFileInfo )
{
char szBaseFilename[ MAX_PATH ];
V_FileBase( pFileInfo->m_pchFileName, szBaseFilename, sizeof( szBaseFilename ) );
if ( V_stricmp( pchMapName, szBaseFilename ) == 0 )
{
return true;
}
}
}
return false;
}
bool CSGOWorkshopMaps::IsFeaturedMap( const char *pchMapName, bool bOnlyOnDisk )
{
for ( int i = 0; i < m_vecCommunityMapsQueue.Count(); ++i )
{
if ( false )
return true;
}
return false;
}
bool CSGOWorkshopMaps::CreateMapFileRequest( const PublishedFileInfo_t &info )
{
// Grab the map file
return WorkshopManager().CreateFileDownloadRequest( info.m_hFile,
info.m_nPublishedFileId,
CFmtStr( "%s/%llu", COMMUNITY_MAP_PATH, info.m_nPublishedFileId ),
V_GetFileName( info.m_pchFileName ),
UGC_PRIORITY_BSP,
info.m_rtimeUpdated );
}
bool CSGOWorkshopMaps::CreateThumbnailFileRequest( const PublishedFileInfo_t &info )
{
// Grab the thumbnail file
return WorkshopManager().CreateFileDownloadRequest( info.m_hPreviewFile,
info.m_nPublishedFileId,
CFmtStr( "%s/%llu", COMMUNITY_MAP_PATH, info.m_nPublishedFileId ),
CFmtStr( "%s%llu.jpg", COMMUNITY_MAP_THUMBNAIL_PREFIX, info.m_nPublishedFileId ),
UGC_PRIORITY_THUMBNAIL,
info.m_rtimeUpdated );
}
// Gets a map file from the workshop without subscribing to it. This is needed for joining servers
// running community maps
void CSGOWorkshopMaps::DownloadMapFile( PublishedFileId_t id )
{
CCommunityMapRequest *pMapRequest = new CCommunityMapRequest( id, 0 );
WorkshopManager().AddFileInfoQuery( pMapRequest, true );
// WorkshopManager().SendAllFileInfoQueries(); //
UpdateWorkshopRequests(); // HACK-- When called from engine during level load, we don't get our update calls yet
// so the queries never get sent and the download never begins... Force an update now.
}
float CSGOWorkshopMaps::GetFileDownloadProgress( PublishedFileId_t id ) const
{
// Haven't got the file info yet
if ( WorkshopManager().IsFileInfoRequestStillPending( id ) )
return 0.0f;
const PublishedFileInfo_t *pInfo = WorkshopManager().GetPublishedFileInfoByID( id );
Assert( pInfo );
if ( !pInfo )
return -1.0f; // No info for this file
// Once file is on disk, return 100%
if ( WorkshopManager().GetUGCFileRequestStatus( pInfo->m_hFile ) != UGCFILEREQUEST_FINISHED )
{
float flProgress = WorkshopManager().GetUGCFileDownloadProgress( pInfo->m_hFile );
return clamp( flProgress, 0, 0.99f ); // HACK: Don't return 100% completion until we copy the file to it's final path on disk
}
else
{
return 1.0f; // return 100% once the status is UGCFILEREQUEST_FINISHED
}
}
//-----------------------------------------------------------------------------
// Purpose: The base class handles book keeping we'd like all of our requests to do
//-----------------------------------------------------------------------------
void CBaseCommunityRequest::OnLoaded( PublishedFileInfo_t &info )
{
// Ask Steam for more information about this user, since we'll be displaying their persona / avatar later
steamapicontext->SteamFriends()->RequestUserInformation( info.m_ulSteamIDOwner, false );
// Get voting information about it
g_CSGOWorkshopMaps.AddPublishedFileVoteInfoRequest( (const PublishedFileInfo_t *) &info);
}
//-----------------------------------------------------------------------------
// Purpose: Grab the thumbnail for our queue history
//-----------------------------------------------------------------------------
void CCommunityMapRequest::OnLoaded( PublishedFileInfo_t &info )
{
// Install our data here
info.m_rtimeSubscribed = m_unSubscribeTime;
BaseClass::OnLoaded( info );
// Grab the thumbnail
bool bCreatedThumbRequest = g_CSGOWorkshopMaps.CreateThumbnailFileRequest( info );
Assert( bCreatedThumbRequest );
if ( bCreatedThumbRequest == false )
{
Log_Warning( LOG_WORKSHOP, "Unable to create thumbnail request for %llu!\n", info.m_nPublishedFileId );
}
// Grab the content file
bool bCreateMapRequest = g_CSGOWorkshopMaps.CreateMapFileRequest( info );
Assert( bCreateMapRequest );
if ( bCreateMapRequest == false )
{
Log_Warning( LOG_WORKSHOP, "Unable to create content file request for %llu!\n", info.m_nPublishedFileId );
}
IGameEvent* pEvent = gameeventmanager->CreateEvent( "ugc_map_info_received" );
if ( pEvent )
{
pEvent->SetUint64( "published_file_id", GetTargetID() );
gameeventmanager->FireEventClientSide( pEvent );
}
}
//-----------------------------------------------------------------------------
// Purpose: Handle error case for community map requests
//-----------------------------------------------------------------------------
void CCommunityMapRequest::OnError( EResult nErrorCode )
{
// If the file is now gone, unsubscribe from it
if ( nErrorCode == k_EResultFileNotFound )
{
g_CSGOWorkshopMaps.UnsubscribeFromMap( GetTargetID() );
}
IGameEvent* pEvent = gameeventmanager->CreateEvent( "ugc_map_download_error" );
if ( pEvent )
{
pEvent->SetUint64( "published_file_id", GetTargetID() );
pEvent->SetInt( "error_code", nErrorCode );
gameeventmanager->FireEventClientSide( pEvent );
}
g_CSGOWorkshopMaps.RemoveCommunityMap( GetTargetID() );
}
//-----------------------------------------------------------------------------
// Purpose: Pop up the overlay showing the requested community map page
//-----------------------------------------------------------------------------
bool CSGOWorkshopMaps::ViewCommunityMapInWorkshop( PublishedFileId_t nFileID )
{
if ( steamapicontext && steamapicontext->SteamUser() && steamapicontext->SteamUtils() && steamapicontext->SteamFriends() && steamapicontext->SteamUtils() )
{
// Overlay is disabled
if( !steamapicontext->SteamUtils()->IsOverlayEnabled() )
return false;
EUniverse eUniverse = steamapicontext && steamapicontext->SteamUtils()
? steamapicontext->SteamUtils()->GetConnectedUniverse()
: k_EUniverseInvalid;
if ( eUniverse == k_EUniverseInvalid )
return false;
char szDestURL[MAX_PATH];
const char *lpszDomanPrefix = ( eUniverse == k_EUniverseBeta ) ? "beta" : "www";
V_snprintf( szDestURL, ARRAYSIZE(szDestURL), "http://%s.steamcommunity.com/sharedfiles/filedetails/?id=%llu", lpszDomanPrefix, nFileID );
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( szDestURL );
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Pop up the overlay to allow users to browse the Workshop
//-----------------------------------------------------------------------------
bool CSGOWorkshopMaps::ViewAllCommunityMapsInWorkshop( void )
{
if ( steamapicontext && steamapicontext->SteamUser() && steamapicontext->SteamFriends() && steamapicontext->SteamUtils() )
{
// Overlay is disabled
if( !steamapicontext->SteamUtils()->IsOverlayEnabled() )
return false;
EUniverse eUniverse = steamapicontext && steamapicontext->SteamUtils()
? steamapicontext->SteamUtils()->GetConnectedUniverse()
: k_EUniverseInvalid;
if ( eUniverse == k_EUniverseInvalid )
return false;
char szDestURL[MAX_PATH];
const char *lpszDomanPrefix = ( eUniverse == k_EUniverseBeta ) ? "beta" : "www";
V_snprintf( szDestURL, ARRAYSIZE(szDestURL), "http://%s.steamcommunity.com/workshop/browse?appid=%d", lpszDomanPrefix, steamapicontext->SteamUtils()->GetAppID() );
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( szDestURL );
return true;
}
return false;
}
bool CSGOWorkshopMaps::WasFileRecentlyUpdated( PublishedFileId_t id ) const
{
/** Removed for partner depot **/
return false;
}
#endif // !_GAMECONSOLE
+129
View File
@@ -0,0 +1,129 @@
//====== Copyright Valve Corporation, All rights reserved. =================
//
// Requests subscribed maps from the workshop, holds a list of them along with metadata.
// NOTE: This could probably all just live in whatever UI element lets the user see/edit
// the list of subscribed maps.
//
//=============================================================================
#if !defined CS_WORKSHOP_MANAGER_H
#define CS_WORKSHOP_MANAGER_H
#if defined( COMPILER_MSVC )
#pragma once
#endif
#if !defined ( _GAMECONSOLE ) && !defined ( NO_STEAM )
#include "ugc_request_manager.h"
#include "ugc_file_info_manager.h"
#include "ugc_workshop_manager.h"
#include "igamesystem.h"
enum {
UGC_PRIORITY_GENERIC = 0,
UGC_PRIORITY_BSP,
UGC_PRIORITY_THUMBNAIL
};
// Handle file requests for community maps (downloads thumbnail / content)
class CBaseCommunityRequest : public CBasePublishedFileRequest
{
public:
CBaseCommunityRequest( PublishedFileId_t nFileID ) :
CBasePublishedFileRequest( nFileID )
{}
virtual void OnLoaded( PublishedFileInfo_t &info );
};
// Handle file requests for community maps (downloads thumbnail / content)
class CCommunityMapRequest : public CBaseCommunityRequest
{
public:
typedef CBaseCommunityRequest BaseClass;
CCommunityMapRequest( PublishedFileId_t nFileID, uint32 nSubscribeTime ) :
BaseClass( nFileID ),
m_unSubscribeTime( nSubscribeTime )
{}
virtual void OnLoaded( PublishedFileInfo_t &info );
virtual void OnError( EResult nErrorCode );
uint32 m_unSubscribeTime;
};
// Autogamesystem to request user maps on startup and call update on the workshop manager.
class CSGOWorkshopMaps : public CAutoGameSystemPerFrame, public CBaseWorkshopManagerCallbackInterface
{
public:
CSGOWorkshopMaps();
virtual bool Init( void ) OVERRIDE;
virtual void Shutdown( void ) OVERRIDE;
virtual void Update( float frametime ) OVERRIDE;
virtual const char* Name( void ) OVERRIDE { return "CSGOWorkshop"; }
bool CreateThumbnailFileRequest( const PublishedFileInfo_t &info );
bool CreateMapFileRequest( const PublishedFileInfo_t &info );
bool AddPublishedFileVoteInfoRequest( const PublishedFileInfo_t *pInfo, bool bForceUpdate = false );
bool UnsubscribeFromMap( PublishedFileId_t nMapID );
bool RemoveCommunityMap( PublishedFileId_t nID );
// Enumeration of subscribed files by this user
CCallResult<CSGOWorkshopMaps, RemoteStorageEnumerateUserSubscribedFilesResult_t> m_callbackEnumerateSubscribedMaps;
void Steam_OnEnumerateSubscribedMaps( RemoteStorageEnumerateUserSubscribedFilesResult_t *pResult, bool bError );
// CBaseWorkshopManagerCallbackInterface
virtual void OnFileRequestFinished( UGCHandle_t hFileHandle ) OVERRIDE;
virtual void OnFileRequestError( UGCHandle_t hFileHandle ) OVERRIDE;
// Published files
virtual void OnPublishedFileSubscribed( PublishedFileId_t nID ) OVERRIDE;
virtual void OnPublishedFileUnsubscribed( PublishedFileId_t nID ) OVERRIDE;
virtual void OnPublishedFileDeleted( PublishedFileId_t nID ) OVERRIDE;
bool IsSubscribedMap( const char *pchMapName, bool bOnlyOnDisk );
bool IsFeaturedMap( const char *pchMapName, bool bOnlyOnDisk );
// Makes sure the latest version of the given ugc item is on disk.
// This does not subscribe to the content and is intended for downloading
// maps the server requires in order to play.
void DownloadMapFile( PublishedFileId_t id );
// Return download progress from 0.0 - 1.0, or -1.0 on error
float GetFileDownloadProgress( PublishedFileId_t id ) const;
bool ViewCommunityMapInWorkshop( PublishedFileId_t nFileID );
bool ViewAllCommunityMapsInWorkshop( void );
// returns reference to a list of subscribed community maps
const CUtlVector< PublishedFileId_t >& GetSubscribedMapList() { return m_vecCommunityMapsQueue; }
bool WasFileRecentlyUpdated( PublishedFileId_t id ) const;
bool EnumerateMapsFailed( void ) const { return m_bEnumerateMapsFailed; }
private:
bool m_bUGCRequestsPaused;
bool m_bEnumerateMapsFailed;
CUtlVector< PublishedFileId_t > m_vecCommunityMapsQueue;
int m_nTotalSubscriptionsLoaded; // Number of subscriptions we've received from the Steam server. This may not be the total number available, meaning we need to requery.
bool m_bReceivedQueueBaseline; // Whether or not we've heard back successfully from Steam on our queue status
float m_flQueueBaselineRequestTime; // Time that the baseline was requested from the GC
void UpdateWorkshopRequests( void );
void QueryForCommunityMaps( void );
void AddCommunityMap( PublishedFileId_t nMapID, uint32 nSubscribeTime );
};
extern CSGOWorkshopMaps g_CSGOWorkshopMaps;
CWorkshopManager &WorkshopManager( void );
#endif // !_GAMECONSOLE && !NO_STEAM
#endif // CS_WORKSHOP_MANAGER_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,444 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef CSGO_PLAYERANIMSTATE_H
#define CSGO_PLAYERANIMSTATE_H
#ifdef _WIN32
#pragma once
#endif
#include "iplayeranimstate.h"
#include "studio.h"
#include "sequence_Transitioner.h"
#include "cs_weapon_parse.h"
#ifdef CLIENT_DLL
#define CCSPlayer C_CSPlayer
#endif
class CCSPlayer;
enum animstate_layer_t
{
ANIMATION_LAYER_AIMMATRIX = 0,
ANIMATION_LAYER_WEAPON_ACTION,
ANIMATION_LAYER_WEAPON_ACTION_RECROUCH,
ANIMATION_LAYER_ADJUST,
ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL,
ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB,
ANIMATION_LAYER_MOVEMENT_MOVE,
ANIMATION_LAYER_MOVEMENT_STRAFECHANGE,
ANIMATION_LAYER_WHOLE_BODY,
ANIMATION_LAYER_FLASHED,
ANIMATION_LAYER_FLINCH,
ANIMATION_LAYER_ALIVELOOP,
ANIMATION_LAYER_LEAN,
ANIMATION_LAYER_COUNT,
};
#define USE_ANIMLAYER_RAW_INDEX false
typedef const int* animlayerpreset;
#define get_animlayerpreset( _n ) s_animLayerOrder ## _n
#define REGISTER_ANIMLAYER_ORDER( _n ) static const int s_animLayerOrder ## _n [ANIMATION_LAYER_COUNT]
REGISTER_ANIMLAYER_ORDER( Default ) = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
// animations can trigger the player to re-order their layers according to hardcoded presets, e.g.:
REGISTER_ANIMLAYER_ORDER( WeaponPost ) = {
ANIMATION_LAYER_AIMMATRIX,
ANIMATION_LAYER_WEAPON_ACTION_RECROUCH,
ANIMATION_LAYER_ADJUST,
ANIMATION_LAYER_MOVEMENT_JUMP_OR_FALL,
ANIMATION_LAYER_MOVEMENT_LAND_OR_CLIMB,
ANIMATION_LAYER_MOVEMENT_MOVE,
ANIMATION_LAYER_MOVEMENT_STRAFECHANGE,
ANIMATION_LAYER_WEAPON_ACTION,
ANIMATION_LAYER_WHOLE_BODY,
ANIMATION_LAYER_FLASHED,
ANIMATION_LAYER_FLINCH,
ANIMATION_LAYER_ALIVELOOP,
ANIMATION_LAYER_LEAN,
};
enum animstate_pose_param_idx_t
{
PLAYER_POSE_PARAM_FIRST = 0,
PLAYER_POSE_PARAM_LEAN_YAW = PLAYER_POSE_PARAM_FIRST,
PLAYER_POSE_PARAM_SPEED,
PLAYER_POSE_PARAM_LADDER_SPEED,
PLAYER_POSE_PARAM_LADDER_YAW,
PLAYER_POSE_PARAM_MOVE_YAW,
PLAYER_POSE_PARAM_RUN,
PLAYER_POSE_PARAM_BODY_YAW,
PLAYER_POSE_PARAM_BODY_PITCH,
PLAYER_POSE_PARAM_DEATH_YAW,
PLAYER_POSE_PARAM_STAND,
PLAYER_POSE_PARAM_JUMP_FALL,
PLAYER_POSE_PARAM_AIM_BLEND_STAND_IDLE,
PLAYER_POSE_PARAM_AIM_BLEND_CROUCH_IDLE,
PLAYER_POSE_PARAM_STRAFE_DIR,
PLAYER_POSE_PARAM_AIM_BLEND_STAND_WALK,
PLAYER_POSE_PARAM_AIM_BLEND_STAND_RUN,
PLAYER_POSE_PARAM_AIM_BLEND_CROUCH_WALK,
PLAYER_POSE_PARAM_MOVE_BLEND_WALK,
PLAYER_POSE_PARAM_MOVE_BLEND_RUN,
PLAYER_POSE_PARAM_MOVE_BLEND_CROUCH_WALK,
//PLAYER_POSE_PARAM_STRAFE_CROSS,
PLAYER_POSE_PARAM_COUNT,
};
struct animstate_pose_param_cache_t
{
bool m_bInitialized;
int m_nIndex;
const char* m_szName;
animstate_pose_param_cache_t()
{
m_bInitialized = false;
m_nIndex = -1;
m_szName = "";
}
int GetIndex( void );
float GetValue( CCSPlayer* pPlayer );
void SetValue( CCSPlayer* pPlayer, float flValue );
bool Init( CCSPlayer* pPlayer, const char* szPoseParamName );
};
#define MAX_ANIMSTATE_ANIMNAME_CHARS 64
#define ANIM_TRANSITION_WALK_TO_RUN 0
#define ANIM_TRANSITION_RUN_TO_WALK 1
//these correlate to the CSWeaponType enum
const char* const g_szWeaponPrefixLookupTable[] = {
"knife",
"pistol",
"smg",
"rifle",
"shotgun",
"sniper",
"heavy",
"c4",
"grenade",
"knife"
};
struct procedural_foot_t
{
Vector m_vecPosAnim;
Vector m_vecPosAnimLast;
Vector m_vecPosPlant;
Vector m_vecPlantVel;
float m_flLockAmount;
float m_flLastPlantTime;
procedural_foot_t()
{
m_vecPosAnim.Init();
m_vecPosAnimLast.Init();
m_vecPosPlant.Init();
m_vecPlantVel.Init();
m_flLockAmount = 0;
m_flLastPlantTime = gpGlobals->curtime;
}
void Init( Vector vecNew )
{
m_vecPosAnim = vecNew;
m_vecPosAnimLast = vecNew;
m_vecPosPlant = vecNew;
m_vecPlantVel.Init();
m_flLockAmount = 0;
m_flLastPlantTime = gpGlobals->curtime;
}
};
struct aimmatrix_transition_t
{
float m_flDurationStateHasBeenValid;
float m_flDurationStateHasBeenInValid;
float m_flHowLongToWaitUntilTransitionCanBlendIn;
float m_flHowLongToWaitUntilTransitionCanBlendOut;
float m_flBlendValue;
void UpdateTransitionState( bool bStateShouldBeValid, float flTimeInterval, float flSpeed )
{
if ( bStateShouldBeValid )
{
m_flDurationStateHasBeenInValid = 0;
m_flDurationStateHasBeenValid += flTimeInterval;
if ( m_flDurationStateHasBeenValid >= m_flHowLongToWaitUntilTransitionCanBlendIn )
{
m_flBlendValue = Approach( 1, m_flBlendValue, flSpeed );
}
}
else
{
m_flDurationStateHasBeenValid = 0;
m_flDurationStateHasBeenInValid += flTimeInterval;
if ( m_flDurationStateHasBeenInValid >= m_flHowLongToWaitUntilTransitionCanBlendOut )
{
m_flBlendValue = Approach( 0, m_flBlendValue, flSpeed );
}
}
}
void Init( void )
{
m_flDurationStateHasBeenValid = 0;
m_flDurationStateHasBeenInValid = 0;
m_flHowLongToWaitUntilTransitionCanBlendIn = 0.3f;
m_flHowLongToWaitUntilTransitionCanBlendOut = 0.3f;
m_flBlendValue = 0;
}
aimmatrix_transition_t()
{
Init();
}
};
class CCSGOPlayerAnimState
{
public:
DECLARE_CLASS_NOBASE( CCSGOPlayerAnimState );
CCSGOPlayerAnimState( CCSPlayer *pPlayer );
void Reset( void );
void Release( void ) { delete this; }
void Update( float eyeYaw, float eyePitch, bool bForce = false );
float GetPrimaryCycle( void ) { return m_flPrimaryCycle; }
void SetUpVelocity( void );
void SetUpAimMatrix( void );
void SetUpWeaponAction( void );
void SetUpMovement( void );
void SetUpAliveloop( void );
void SetUpWholeBodyAction( void );
void SetUpFlashedReaction( void );
void SetUpFlinch( void );
void SetUpLean( void );
void UpdateAnimLayer( animstate_layer_t nLayerIndex, int nSequence, float flPlaybackRate, float flWeight, float flCycle = 0 );
void IncrementLayerCycleWeightRateGeneric( animstate_layer_t nLayerIndex );
void IncrementLayerCycle( animstate_layer_t nLayerIndex, bool bAllowLoop = false );
void IncrementLayerWeight( animstate_layer_t nLayerIndex );
void SetLayerRate( animstate_layer_t nLayerIndex, float flRate );
void SetLayerCycle( animstate_layer_t nLayerIndex, float flCycle );
void SetLayerWeight( animstate_layer_t nLayerIndex, float flWeight );
void SetLayerWeightRate( animstate_layer_t nLayerIndex, float flPrevious );
void SetLayerSequence( animstate_layer_t nLayerIndex, int nSequence );
float GetLayerWeight( animstate_layer_t nLayerIndex );
float GetLayerIdealWeightFromSeqCycle( animstate_layer_t nLayerIndex );
float GetLayerRate( animstate_layer_t nLayerIndex );
float GetLayerCycle( animstate_layer_t nLayerIndex );
int GetLayerSequence( animstate_layer_t nLayerIndex );
Activity GetLayerActivity( animstate_layer_t nLayerIndex );
bool IsLayerSequenceCompleted( animstate_layer_t nLayerIndex );
bool LayerSequenceHasActMod( animstate_layer_t nLayerIndex, const char* szActMod );
void WriteAnimstateDebugBuffer( char *pDest );
void ApplyLayerOrderPreset( animlayerpreset nNewPreset, bool bForce = false );
void UpdateLayerOrderPreset( animstate_layer_t nLayerIndex, int nSequence );
animlayerpreset m_pLayerOrderPreset;
bool m_bFirstRunSinceInit;
void ModifyEyePosition( Vector& vecInputEyePos );
#ifdef CLIENT_DLL
bool m_bFirstFootPlantSinceInit;
void DoProceduralFootPlant( matrix3x4a_t boneToWorld[], mstudioikchain_t *pLeftFootChain, mstudioikchain_t *pRightFootChain, BoneVector pos[] );
int m_iLastUpdateFrame;
float m_flEyePositionSmoothLerp;
void OnClientWeaponChange( CWeaponCSBase* pCurrentWeapon );
float m_flStrafeChangeWeightSmoothFalloff;
void NotifyOnLayerChangeSequence( const CAnimationLayer* pLayer, const int nNewSequence );
void NotifyOnLayerChangeWeight( const CAnimationLayer* pLayer, const float flNewWeight );
void NotifyOnLayerChangeCycle( const CAnimationLayer* pLayer, const float flNewcycle );
#endif
#ifndef CLIENT_DLL
void AddActivityModifier( const char *szName );
void UpdateActivityModifiers( void );
int SelectSequenceFromActMods( Activity iAct );
void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 );
void SelectDeathPose( const CTakeDamageInfo &info, int hitgroup, Activity& activity, float& yaw );
#endif
#ifndef CLIENT_DLL
float m_flFlashedAmountEaseOutStart;
float m_flFlashedAmountEaseOutEnd;
#endif
private:
aimmatrix_transition_t m_tStandWalkAim;
aimmatrix_transition_t m_tStandRunAim;
aimmatrix_transition_t m_tCrouchWalkAim;
bool LayerToIndex( const CAnimationLayer* pLayer, int &nIndex );
float LerpCrouchWalkRun( float flCrouchVal, float flWalkVal, float flRunVal );
bool CacheSequences( void );
const char* GetWeaponPrefix( void );
int m_cachedModelIndex;
#ifdef CLIENT_DLL
float FootBarrierEq( float flIn, float flMinWidth );
float m_flStepHeightLeft;
float m_flStepHeightRight;
CWeaponCSBase* m_pWeaponLastBoneSetup;
#endif
CCSPlayer* m_pPlayer;
CWeaponCSBase* m_pWeapon;
CWeaponCSBase* m_pWeaponLast;
float m_flLastUpdateTime;
int m_nLastUpdateFrame;
float m_flLastUpdateIncrement;
float m_flEyeYaw;
float m_flEyePitch;
float m_flFootYaw;
float m_flFootYawLast;
float m_flMoveYaw;
float m_flMoveYawIdeal;
float m_flMoveYawCurrentToIdeal;
float m_flTimeToAlignLowerBody;
float m_flPrimaryCycle;
float m_flMoveWeight;
float m_flMoveWeightSmoothed;
float m_flAnimDuckAmount;
float m_flDuckAdditional;
float m_flRecrouchWeight;
Vector m_vecPositionCurrent;
Vector m_vecPositionLast;
Vector m_vecVelocity;
Vector m_vecVelocityNormalized;
Vector m_vecVelocityNormalizedNonZero;
float m_flVelocityLengthXY;
float m_flVelocityLengthZ;
float m_flSpeedAsPortionOfRunTopSpeed;
float m_flSpeedAsPortionOfWalkTopSpeed;
float m_flSpeedAsPortionOfCrouchTopSpeed;
float m_flDurationMoving;
float m_flDurationStill;
bool m_bOnGround;
#ifndef CLIENT_DLL
bool m_bJumping;
float m_flLowerBodyRealignTimer;
#endif
bool m_bLanding;
float m_flJumpToFall;
float m_flDurationInAir;
float m_flLeftGroundHeight;
float m_flLandAnimMultiplier;
float m_flWalkToRunTransition;
bool m_bLandedOnGroundThisFrame;
bool m_bLeftTheGroundThisFrame;
float m_flInAirSmoothValue;
bool m_bOnLadder;
float m_flLadderWeight;
float m_flLadderSpeed;
bool m_bWalkToRunTransitionState;
bool m_bDefuseStarted;
bool m_bPlantAnimStarted;
bool m_bTwitchAnimStarted;
bool m_bAdjustStarted;
CUtlVector<CUtlSymbol> m_ActivityModifiers;
float m_flNextTwitchTime;
float m_flTimeOfLastKnownInjury;
float m_flLastVelocityTestTime;
Vector m_vecVelocityLast;
Vector m_vecTargetAcceleration;
Vector m_vecAcceleration;
float m_flAccelerationWeight;
float m_flAimMatrixTransition;
float m_flAimMatrixTransitionDelay;
bool m_bFlashed;
float m_flStrafeChangeWeight;
float m_flStrafeChangeTargetWeight;
float m_flStrafeChangeCycle;
int m_nStrafeSequence;
bool m_bStrafeChanging;
float m_flDurationStrafing;
float m_flFootLerp;
bool m_bFeetCrossed;
bool m_bPlayerIsAccelerating;
animstate_pose_param_cache_t m_tPoseParamMappings[ PLAYER_POSE_PARAM_COUNT ];
#ifndef CLIENT_DLL
bool m_bDeployRateLimiting;
#endif
float m_flDurationMoveWeightIsTooHigh;
float m_flStaticApproachSpeed;
int m_nPreviousMoveState;
float m_flStutterStep;
float m_flActionWeightBiasRemainder;
#ifdef CLIENT_DLL
procedural_foot_t m_footLeft;
procedural_foot_t m_footRight;
float m_flCameraSmoothHeight;
bool m_bSmoothHeightValid;
float m_flLastTimeVelocityOverTen;
#endif
float m_flAimYawMin;
float m_flAimYawMax;
float m_flAimPitchMin;
float m_flAimPitchMax;
//float m_flMoveWalkWeight;
//float m_flMoveCrouchWalkWeight;
//float m_flMoveRunWeight;
int m_nAnimstateModelVersion;
};
CCSGOPlayerAnimState *CreateCSGOPlayerAnimstate( CBaseAnimatingOverlay *pEntity );
#endif // CSGO_PLAYERANIMSTATE_H
@@ -0,0 +1,808 @@
//====== Copyright (C), Valve Corporation, All rights reserved. =======
//
// Purpose: This file defines all of our over-the-wire net protocols for the
// Game Coordinator for CS:GO. Note that we never use types
// with undefined length (like int). Always use an explicit type
// (like int32).
//
//=============================================================================
#ifndef CSTRIKE15_GCCONSTANTS_H
#define CSTRIKE15_GCCONSTANTS_H
#ifdef _WIN32
#pragma once
#endif
//=============================================================================
enum EMsgGCCStrike15_v2_ClientLogonFatalError
{
k_EMsgGCCStrike15_v2_ClientLogonFatalError_None = 0, // Should not be used (default = no error and logon can succeed)
k_EMsgGCCStrike15_v2_ClientLogonFatalError_MustUsePWLauncher = 1, // Client must use PW launcher
k_EMsgGCCStrike15_v2_ClientLogonFatalError_MustUseSteamLauncher = 2, // Client must use Steam launcher
k_EMsgGCCStrike15_v2_ClientLogonFatalError_AccountLinkPWMissing = 3, // Client hasn't linked their Steam and PW accounts
k_EMsgGCCStrike15_v2_ClientLogonFatalError_CustomMessageBase = 1000, // Custom message has been provided by the 3rd party server (Perfect World)
};
//=============================================================================
enum EMsgGCCStrike15_v2_MatchmakingState_t
{
k_EMsgGCCStrike15_v2_MatchmakingState_None = 0, // Client is not in matchmaking pool
k_EMsgGCCStrike15_v2_MatchmakingState_Joined = 1, // Client joined matchmaking pool
k_EMsgGCCStrike15_v2_MatchmakingState_Searching = 2, // Client is searching in matchmaking pool for some time
k_EMsgGCCStrike15_v2_MatchmakingState_BackToSearching = 3, // Client has a match which failed to get confirmed by other players
k_EMsgGCCStrike15_v2_MatchmakingState_MatchConfirmed = 4, // Client's match is confirmed and client is removed from matchmaking pool
};
//=============================================================================
enum EMsgGCCStrike15_v2_MatchmakingMatchOutcome_t
{
k_EMsgGCCStrike15_v2_MatchmakingMatchOutcome_ResultMask = 0x3, // Typical match result ( 0 = tie, 1 = first team wins, 2 = second team wins, 3 = legacy incomplete )
k_EMsgGCCStrike15_v2_MatchmakingMatchOutcome_Flag_NetworkEvent = 0x4, // Network event occurred during the match
};
//=============================================================================
enum EMsgGCCStrike15_v2_MatchmakingGameComposition_t
{
k_EMsgGCCStrike15_v2_MatchmakingGameComposition_bits_Game = 7,
k_EMsgGCCStrike15_v2_MatchmakingGameComposition_bits_MapGroup = 24,
};
enum EMsgGCCStrike15_v2_MatchmakingGame_t // & 0xF (values from 1 to 15)
{
// 1 .. 2 .. 3 are available
k_EMsgGCCStrike15_v2_MatchmakingGame_ArmsRace = 4,
k_EMsgGCCStrike15_v2_MatchmakingGame_Demolition = 5,
k_EMsgGCCStrike15_v2_MatchmakingGame_Deathmatch = 6,
k_EMsgGCCStrike15_v2_MatchmakingGame_ClassicCasual = 7,
k_EMsgGCCStrike15_v2_MatchmakingGame_ClassicCompetitive = 8, // Used since October 2012
k_EMsgGCCStrike15_v2_MatchmakingGame_Cooperative = 9,
k_EMsgGCCStrike15_v2_MatchmakingGame_ScrimComp2v2 = 10, // Used since April 2017
k_EMsgGCCStrike15_v2_MatchmakingGame_ScrimComp5v5 = 11, // Used since April 2017
k_EMsgGCCStrike15_v2_MatchmakingGame_Skirmish = 12, // Used since April 2017
// 11 .. 15 are available
};
enum EPlayerRankPipsTypeID_t // STORED IN SQL!
{
k_EPlayerRankPipsTypeID_Undefined = 0, // should never be used
k_EPlayerRankPipsTypeID_ScrimComp2v2_2017 = 1, // Spring 2017 comp 2v2
k_EPlayerRankPipsTypeID_ScrimComp5v5_2017 = 2, // Spring 2017 comp 5v5 weapons expert
};
enum EMsgGCCStrike15_v2_SeasonTime_t
{
k_EMsgGCCStrike15_v2_SeasonTime_2013Autumn = 1392822576, // Operation Bravo ended
k_EMsgGCCStrike15_v2_SeasonTime_2014Winter = 1402958328, // Operation Phoenix ended
k_EMsgGCCStrike15_v2_SeasonTime_2014Summer = 1412899200, // Operation Breakout ended
k_EMsgGCCStrike15_v2_SeasonTime_2015Spring = 1430179200, // Operation Vanguard ended
k_EMsgGCCStrike15_v2_SeasonTime_2015Autumn = 1449089753, // Operation Bloodhound ended
k_EMsgGCCStrike15_v2_SeasonTime_2016Summer = 1472688000, // Operation Wildfire ended
};
enum EMsgGCCStrike15_v2_MatchmakingMapGroup_t // combines with Game_t above, 24 bits available (up to 1<<23)
{
// NOTE: Changing names/values in this enum will break old match info records, which have their
// map group encoded using this enum, and mapped to map name. For details, see
// MatchmakingGameTypeMapToString()
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_dust = ( 1 << 0 ),
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_dust2 = ( 1 << 1 ),
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_train = ( 1 << 2 ),
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_aztec = ( 1 << 3 ),
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_inferno = ( 1 << 4 ),
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_nuke = ( 1 << 5 ),
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_vertigo = ( 1 << 6 ),
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_mirage = ( 1 << 7 ), // (0x080)
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_office = ( 1 << 8 ),
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_italy = ( 1 << 9 ),
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_assault = ( 1 << 10 ),
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_militia = ( 1 << 11 ), // (0x800)
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_cache = ( 1 << 12 ), // Bravo, Phoenix => free
// 13-19 operation maps
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_overpass = ( 1 << 20 ),
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_cbble = ( 1 << 21 ),
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_canals = ( 1 << 22 ),
// 23 free, should be debugged extensively before using as it makes numbers negative (when combined with game type for C++ and SQL)
// k_EMsgGCCStrike15_v2_MatchmakingMapGroup_questionable = ( 1 << 23 ),
// End of Operation Bravo: 1392822576
// Your time zone: 2/19/2014 7:09:36 AM GMT-8
// End of Operation Phoenix: 1402958328
// Your time zone: 6/16/2014 3:38:48 PM GMT-7
// End of Operation Breakout: 1412899200
// Your time zone: 10/9/2014 5:00:00 PM GMT-7
// End of Operation Vanguard: 1430179200
// Your time zone: 4/27/2015, 5:00:00 PM GMT-7
// End of Operation Bloodhound: 1449089753
// Your time zone: 4/27/2015, 5:00:00 PM GMT-7
// End of Operation Wildfire: 1472688000 (significantly before this, actually)
// 9/1/2016, 0:00:00 AM UTC
// defined in Valve main group--
// k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_cache = ( 1 << 12 ), // Bravo, Phoenix => free
// Operation maps (7)
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_map01 = ( 1 << 13 ), // (generic)
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_gwalior = ( 1 << 13 ), // Bravo
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_motel = ( 1 << 13 ), // Phoenix
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_rush = ( 1 << 13 ), // Breakout
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_season = ( 1 << 13 ), // Vanguard, Bloodhound
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_cruise = ( 1 << 13 ), // Wildfire
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_map02 = ( 1 << 14 ), // (generic)
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_ali = ( 1 << 14 ), // Bravo, Phoenix
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_blackgold = ( 1 << 14 ), // Breakout
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_marquis = ( 1 << 14 ), // Vanguard
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_log = ( 1 << 14 ), // Bloodhound
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_coast = ( 1 << 14 ), // Wildfire
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_map03 = ( 1 << 15 ), // (generic)
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_ruins = ( 1 << 15 ), // Bravo
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_thunder = ( 1 << 15 ), // Phoenix
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_mist = ( 1 << 15 ), // Breakout
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_facade = ( 1 << 15 ), // Vanguard
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_rails = ( 1 << 15 ), // Bloodhound
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_empire = ( 1 << 15 ), // Wildfire
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_map04 = ( 1 << 16 ), // (generic)
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_chinatown = ( 1 << 16 ), // Bravo
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_favela = ( 1 << 16 ), // Phoenix
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_insertion = ( 1 << 16 ), // Breakout
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_backalley = ( 1 << 16 ), // Vanguard
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_resort = ( 1 << 16 ), // Bloodhound
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_mikla = ( 1 << 16 ), // Wildfire
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_map05 = ( 1 << 17 ), // (generic)
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_seaside = ( 1 << 17 ), // Payback, Bravo, Phoenix
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_overgrown = ( 1 << 17 ), // Breakout
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_workout = ( 1 << 17 ), // Vanguard
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_zoo = ( 1 << 17 ), // Bloodhound
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_royal = ( 1 << 17 ), // Wildfire
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_map06 = ( 1 << 18 ), // (generic)
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_siege = ( 1 << 18 ), // Bravo
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_downtown = ( 1 << 18 ), // Phoenix
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_castle = ( 1 << 18 ), // Breakout
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_bazaar = ( 1 << 18 ), // Vanguard
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_santorini = ( 1 << 18 ), // Wildfire
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_map07 = ( 1 << 19 ), // (generic)
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_agency = ( 1 << 19 ), // Bravo, Phoenix, Bloodhound
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_tulip = ( 1 << 19 ), // Wildfire
// defined in Valve main group--
// k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_overpass = ( 1 << 20 ),
// k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_cbble = ( 1 << 21 ),
// k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_canals = ( 1 << 22 ),
//
// NO MORE BITS AVAILABLE HERE UNFORTUNATELY
// ALL ACTIVE MAPGROUPS MUST FIT IN 0xFFFFFF (24 bits, 1<<0 to 1<<23)
// 1<<23 should be debugged extensively before using as it makes numbers negative (when combined with game type for C++ and SQL)
//
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_tournament_maps =
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_inferno |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_nuke |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_mirage |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_train |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_overpass |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_cbble |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_cache |
0,
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_operation_maps =
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_map01 |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_map02 |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_map03 |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_map04 |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_map05 |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_map06 |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_map07 |
0,
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_reserves_maps =
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_dust |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_aztec |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_vertigo |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_canals |
0,
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_hostage_maps =
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_office |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_italy |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_assault |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_cs_militia |
0,
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_all_valid =
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_tournament_maps|
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_dust2 |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_operation_maps |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_reserves_maps |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_hostage_maps |
0,
// --- Begin special mapgroups for non-competitive game modes
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_ar_shoots = ( 1 << 0 ), // AR
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_bank = ( 1 << 0 ), // DEMO + 2v2
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_ar_baggage = ( 1 << 1 ), // AR
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_shorttrain = ( 1 << 1 ), // DEMO + 2v2
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_ar_monastery = ( 1 << 2 ), // AR
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_sugarcane = ( 1 << 2 ), // DEMO + 2v2
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_lake = ( 1 << 3 ), // AR + DEMO + 2v2
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_stmarc = ( 1 << 4 ), // AR + DEMO + 2v2
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_safehouse = ( 1 << 5 ), // AR + DEMO + 2v2
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_shortdust = ( 1 << 6 ), // DEMO + 2v2
// --- combination of special mapgroups for non-competitive game modes
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_AR =
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_ar_shoots |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_ar_baggage |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_ar_monastery |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_lake |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_stmarc |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_safehouse |
0,
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_DEMO =
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_bank |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_shorttrain |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_sugarcane |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_lake |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_stmarc |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_safehouse |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_shortdust |
0,
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_ScrimComp2v2 =
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_bank |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_shorttrain |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_lake |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_stmarc |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_safehouse |
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_shortdust |
0,
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_active = k_EMsgGCCStrike15_v2_MatchmakingMapGroup_tournament_maps, // Active group
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_dust247 = k_EMsgGCCStrike15_v2_MatchmakingMapGroup_de_dust2, // Dust 2 (24x7) group
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_reserves = k_EMsgGCCStrike15_v2_MatchmakingMapGroup_reserves_maps, // Reserves group
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_hostage = k_EMsgGCCStrike15_v2_MatchmakingMapGroup_hostage_maps, // Hostage group
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_op_op07 = k_EMsgGCCStrike15_v2_MatchmakingMapGroup_operation_maps, // Operation 7 group
k_EMsgGCCStrike15_v2_MatchmakingMapGroup_skirmish = ( 1 << 22 ) - 1, // = 0x3fffff. Up to 22 simultaneous skirmish modes are supported
// --- end of special mapgroups for non-competitive game modes
};
enum EMsgGCCStrike15_v2_MatchmakingMap_t
{
//
// WARNING: These constants CANNOT be renumbered as they are stored in SQL!
//
k_EMsgGCCStrike15_v2_MatchmakingMap_undefined = 0,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_dust = 1,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_dust2 = 2,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_train = 3,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_aztec = 4,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_inferno = 5,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_nuke = 6,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_vertigo = 7,
k_EMsgGCCStrike15_v2_MatchmakingMap_cs_office = 8,
k_EMsgGCCStrike15_v2_MatchmakingMap_cs_italy = 9,
k_EMsgGCCStrike15_v2_MatchmakingMap_ar_baggage = 10,
k_EMsgGCCStrike15_v2_MatchmakingMap_ar_baloney = 11,
k_EMsgGCCStrike15_v2_MatchmakingMap_ar_monastery = 12,
k_EMsgGCCStrike15_v2_MatchmakingMap_ar_shoots = 13,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_bank = 14,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_glass = 15,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_lake = 16,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_safehouse = 17,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_shorttrain = 18,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_stmarc = 19,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_sugarcane = 20,
k_EMsgGCCStrike15_v2_MatchmakingMap_cs_assault = 21,
k_EMsgGCCStrike15_v2_MatchmakingMap_cs_militia = 22,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_mirage = 23,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_cache = 24,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_gwalior = 25,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_ali = 26,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_ruins = 27,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_chinatown = 28,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_seaside = 29,
k_EMsgGCCStrike15_v2_MatchmakingMap_cs_siege = 30,
k_EMsgGCCStrike15_v2_MatchmakingMap_cs_agency = 31,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_overpass = 32,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_cbble = 33,
k_EMsgGCCStrike15_v2_MatchmakingMap_cs_motel = 34,
k_EMsgGCCStrike15_v2_MatchmakingMap_cs_downtown = 35,
k_EMsgGCCStrike15_v2_MatchmakingMap_cs_thunder = 36,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_favela = 37,
k_EMsgGCCStrike15_v2_MatchmakingMap_cs_rush = 38,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_mist = 39,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_castle = 40,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_overgrown = 41,
k_EMsgGCCStrike15_v2_MatchmakingMap_cs_insertion = 42,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_blackgold = 43,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_season = 44,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_marquis = 45,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_facade = 46,
k_EMsgGCCStrike15_v2_MatchmakingMap_cs_backalley = 47,
k_EMsgGCCStrike15_v2_MatchmakingMap_cs_workout = 48,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_bazaar = 49,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_shortdust = 50,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_rails = 51,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_resort = 52,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_zoo = 53,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_log = 54,
k_EMsgGCCStrike15_v2_MatchmakingMap_gd_crashsite = 55,
k_EMsgGCCStrike15_v2_MatchmakingMap_gd_lake = 56,
k_EMsgGCCStrike15_v2_MatchmakingMap_gd_bank = 57,
k_EMsgGCCStrike15_v2_MatchmakingMap_gd_cbble = 58,
k_EMsgGCCStrike15_v2_MatchmakingMap_cs_cruise = 59,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_coast = 60,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_empire = 61,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_mikla = 62,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_royal = 63,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_santorini = 64,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_tulip = 65,
k_EMsgGCCStrike15_v2_MatchmakingMap_gd_sugarcane = 66,
k_EMsgGCCStrike15_v2_MatchmakingMap_coop_cementplant = 67,
k_EMsgGCCStrike15_v2_MatchmakingMap_de_canals = 68,
//
// WARNING: These constants CANNOT be renumbered as they are stored in SQL!
//
};
//=============================================================================
enum EMsgGCCStrike15_v2_SessionNeed_t
{
//
// WARNING: These constants CANNOT be renumbered as they are used for client<>gc communication
//
// They represent client state to help GC better schedule logon surges
//
k_EMsgGCCStrike15_v2_SessionNeed_Default = 0,
k_EMsgGCCStrike15_v2_SessionNeed_OnServer = 1,
k_EMsgGCCStrike15_v2_SessionNeed_FindGame = 2,
k_EMsgGCCStrike15_v2_SessionNeed_PartyLobby = 3,
k_EMsgGCCStrike15_v2_SessionNeed_Overwatch = 4,
//
// WARNING: These constants CANNOT be renumbered as they are used for client<>gc communication
//
};
//=============================================================================
enum EMsgGCCStrike15_v2_AccountActivity_t
{
//
// WARNING: These constants CANNOT be renumbered as they are used for client<>gc communication
//
// (0-0xF for compact GC representation)
//
k_EMsgGCCStrike15_v2_AccountActivity_None = 0,
k_EMsgGCCStrike15_v2_AccountActivity_Playing = 1,
k_EMsgGCCStrike15_v2_AccountActivity_SpecConnected = 2,
k_EMsgGCCStrike15_v2_AccountActivity_SpecGOTV = 3,
k_EMsgGCCStrike15_v2_AccountActivity_SpecOverwatch = 4,
k_EMsgGCCStrike15_v2_AccountActivity_SpecTwitch = 5,
k_EMsgGCCStrike15_v2_AccountActivity_count = 6,
//
// WARNING: These constants CANNOT be renumbered as they are used for client<>gc communication
//
k_EMsgGCCStrike15_v2_AccountActivity_RatelimitSeconds = 180, // activity messages are ratelimited
};
//=============================================================================
enum EMsgGCCStrike15_v2_MatchmakingKickBanReason_t
{
//
// WARNING: These constants CANNOT be renumbered as they are stored in SQL!
//
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_VotedOff = 1,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_TKLimit = 2,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_TKSpawn = 3,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_DisconnectedTooLong = 4,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_Abandoned = 5,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_THLimit = 6,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_THSpawn = 7,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_OfficialBan = 8,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_KickedTooMuch = 9,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_ConvictedForCheating = 10,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_ConvictedForBehavior = 11,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_Abandoned_Grace = 12,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_DisconnectedTooLong_Grace = 13,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_ChallengeNotification = 14,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_NoUserSession = 15,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_FailedToConnect = 16,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_KickAbuse = 17,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_SkillGroupCalibration = 18,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_GsltViolation = 19,
k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_GsltViolation_Repeated = 20,
//
// WARNING: These constants CANNOT be renumbered as they are stored in SQL!
//
};
inline bool EMsgGCCStrike15_v2_MatchmakingKickBanReason_IsGlobal( uint32 eReason )
{
switch ( eReason )
{
case k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_OfficialBan:
case k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_ConvictedForCheating:
case k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_ConvictedForBehavior:
case k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_ChallengeNotification:
case k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_GsltViolation:
case k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_GsltViolation_Repeated:
case k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_NoUserSession:
return true;
default:
return false;
}
}
inline bool EMsgGCCStrike15_v2_MatchmakingKickBanReason_IsPermanent( uint32 eReason )
{
switch ( eReason )
{
case k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_OfficialBan:
case k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_ConvictedForCheating:
case k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_ChallengeNotification:
return true;
default:
return false;
}
}
inline bool EMsgGCCStrike15_v2_MatchmakingKickBanReason_IsGreen( uint32 eReason )
{
switch ( eReason )
{
case k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_Abandoned_Grace:
case k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_DisconnectedTooLong_Grace:
case k_EMsgGCCStrike15_v2_MatchmakingKickBanReason_SkillGroupCalibration:
return true;
default:
return false;
}
}
//=============================================================================
enum EMMV2OverwatchCasesVerdict_t
{
// CSGO V2 Overwatch case verdict field, stored in SQL
k_EMMV2OverwatchCasesVerdict_Pending = 0,
k_EMMV2OverwatchCasesVerdict_Dismissed = 1,
k_EMMV2OverwatchCasesVerdict_ConvictedForCheating = 2,
k_EMMV2OverwatchCasesVerdict_ConvictedForBehavior = 3,
};
enum EMMV2OverwatchCasesUpdateReason_t
{
// CSGO V2 Overwatch case update request reason, used for communication between client and GC
k_EMMV2OverwatchCasesUpdateReason_Poll = 0, // Client is polling for an overwatch case
k_EMMV2OverwatchCasesUpdateReason_Assign = 1, // Client is eager to get a case assigned and work on it
k_EMMV2OverwatchCasesUpdateReason_Downloading = 2, // Client is downloading the case files
k_EMMV2OverwatchCasesUpdateReason_Verdict = 3, // Client is willing to cast a verdict on a previously assigned case
};
enum EMMV2OverwatchCasesStatus_t
{
// CSGO V2 Overwatch case status field, stored in SQL
k_EMMV2OverwatchCasesStatus_Default = 0,
k_EMMV2OverwatchCasesStatus_Ready = 1,
k_EMMV2OverwatchCasesStatus_ErrorDownloading = 2,
k_EMMV2OverwatchCasesStatus_ErrorExtracting = 3,
};
enum EMMV2OverwatchCasesType_t
{
// CSGO V2 Overwatch case type field, stored in SQL
k_EMMV2OverwatchCasesType_Reports = 0,
k_EMMV2OverwatchCasesType_Placebo = 1,
k_EMMV2OverwatchCasesType_VACSuspicion = 2,
k_EMMV2OverwatchCasesType_Manual = 3,
k_EMMV2OverwatchCasesType_MLSuspicion = 4,
k_EMMV2OverwatchCasesType_Max = 5,
};
//=============================================================================
inline uint32 MatchmakingGameTypeCompose( EMsgGCCStrike15_v2_MatchmakingGame_t eGame, EMsgGCCStrike15_v2_MatchmakingMapGroup_t eMapGroup )
{
return ( ( uint32( eGame ) & 0xF ) << 0 ) | ( ( uint32( eMapGroup ) & 0xFFFFFF ) << 8 );
}
inline EMsgGCCStrike15_v2_MatchmakingGame_t MatchmakingGameTypeToGame( uint32 uiGameType )
{
return ( EMsgGCCStrike15_v2_MatchmakingGame_t ) ( ( uiGameType >> 0 ) & 0xF );
}
inline EMsgGCCStrike15_v2_MatchmakingMapGroup_t MatchmakingGameTypeToMapGroup( uint32 uiGameType )
{
return ( EMsgGCCStrike15_v2_MatchmakingMapGroup_t ) ( ( uiGameType >> 8 ) & 0xFFFFFF );
}
inline EPlayerRankPipsTypeID_t MatchmakingGameTypeToPipsTypeID( uint32 uiGameType )
{
switch ( MatchmakingGameTypeToGame( uiGameType ) )
{
case k_EMsgGCCStrike15_v2_MatchmakingGame_ScrimComp2v2:
return k_EPlayerRankPipsTypeID_ScrimComp2v2_2017;
case k_EMsgGCCStrike15_v2_MatchmakingGame_ScrimComp5v5:
return k_EPlayerRankPipsTypeID_ScrimComp5v5_2017;
default:
return k_EPlayerRankPipsTypeID_Undefined;
}
}
inline bool MatchmakingGameTypeGameIsQueued( EMsgGCCStrike15_v2_MatchmakingGame_t eGame )
{
switch ( eGame )
{
case k_EMsgGCCStrike15_v2_MatchmakingGame_ClassicCompetitive:
case k_EMsgGCCStrike15_v2_MatchmakingGame_Cooperative:
case k_EMsgGCCStrike15_v2_MatchmakingGame_ScrimComp2v2:
case k_EMsgGCCStrike15_v2_MatchmakingGame_ScrimComp5v5:
return true;
default:
return false;
}
}
inline bool MatchmakingGameTypeGameIsQueuedWithMostStats( EMsgGCCStrike15_v2_MatchmakingGame_t eGame )
{
switch ( eGame )
{
case k_EMsgGCCStrike15_v2_MatchmakingGame_ClassicCompetitive:
case k_EMsgGCCStrike15_v2_MatchmakingGame_ScrimComp2v2:
case k_EMsgGCCStrike15_v2_MatchmakingGame_ScrimComp5v5:
return true;
default:
return false;
}
}
inline bool MatchmakingGameTypeGameIsQueuedWithFullMatchStats( EMsgGCCStrike15_v2_MatchmakingGame_t eGame )
{
switch ( eGame )
{
case k_EMsgGCCStrike15_v2_MatchmakingGame_ClassicCompetitive:
return true;
default:
return false;
}
}
inline bool MatchmakingGameTypeGameIsSingleMapGroup( EMsgGCCStrike15_v2_MatchmakingGame_t eGame )
{
switch ( eGame )
{
case k_EMsgGCCStrike15_v2_MatchmakingGame_Cooperative:
case k_EMsgGCCStrike15_v2_MatchmakingGame_Skirmish:
return true;
default:
return false;
}
}
inline EMsgGCCStrike15_v2_MatchmakingMapGroup_t MatchmakingGameTypeMapGroupExtendToLargeGroup( EMsgGCCStrike15_v2_MatchmakingGame_t eGame, EMsgGCCStrike15_v2_MatchmakingMapGroup_t eGroup )
{
switch ( eGame )
{
case k_EMsgGCCStrike15_v2_MatchmakingGame_ArmsRace:
return k_EMsgGCCStrike15_v2_MatchmakingMapGroup_AR;
case k_EMsgGCCStrike15_v2_MatchmakingGame_Demolition:
return k_EMsgGCCStrike15_v2_MatchmakingMapGroup_DEMO;
case k_EMsgGCCStrike15_v2_MatchmakingGame_Deathmatch:
case k_EMsgGCCStrike15_v2_MatchmakingGame_ClassicCasual:
#define MAPGROUPENUM( mgname ) if ( k_EMsgGCCStrike15_v2_MatchmakingMapGroup_##mgname & eGroup ) return k_EMsgGCCStrike15_v2_MatchmakingMapGroup_##mgname;
/** Removed for partner depot **/
#undef MAPGROUPENUM
return eGroup;
default:
return eGroup;
}
}
inline uint32 MatchmakingGameTypeGameMaxPlayers( EMsgGCCStrike15_v2_MatchmakingGame_t eGame )
{
switch ( eGame )
{
case k_EMsgGCCStrike15_v2_MatchmakingGame_ArmsRace: return 10;
case k_EMsgGCCStrike15_v2_MatchmakingGame_Demolition: return 10;
case k_EMsgGCCStrike15_v2_MatchmakingGame_Deathmatch: return 16;
case k_EMsgGCCStrike15_v2_MatchmakingGame_ClassicCasual: return 20;
case k_EMsgGCCStrike15_v2_MatchmakingGame_ClassicCompetitive: return 10;
case k_EMsgGCCStrike15_v2_MatchmakingGame_Cooperative: return 2;
case k_EMsgGCCStrike15_v2_MatchmakingGame_ScrimComp2v2: return 4;
case k_EMsgGCCStrike15_v2_MatchmakingGame_ScrimComp5v5: return 10;
case k_EMsgGCCStrike15_v2_MatchmakingGame_Skirmish: return 16; // $$$REI TODO Decide # of players in skirmish. Right now using DM as base.
default: return 10;
}
}
inline char const * MatchmakingGameTypeMapToString( EMsgGCCStrike15_v2_MatchmakingMapGroup_t eMapGroup, uint64 uiMatchID )
{
char const *szMap = NULL;
/** Removed for partner depot **/
return szMap;
}
//=============================================================================
enum EMsgGCCStrike15_v2_WatchInfoConstants_t
{
k_EMsgGCCStrike15_v2_WatchInfoConstants_MaxAccountsBatchSize = 50, // How many accounts can be requested in a batch
k_EMsgGCCStrike15_v2_WatchInfoConstants_MaxAccountsBatchRate = 5, // 5 requests per minute are allowed
};
//=============================================================================
enum EMsgGCCStrike15_v2_GC2ClientMsgType
{
k_EMsgGCCStrike15_v2_GC2ClientMsgType_Unconnected = 0, // Client is Unconnected
k_EMsgGCCStrike15_v2_GC2ClientMsgType_Unauthorized = 1, // Client is Unauthorized
k_EMsgGCCStrike15_v2_GC2ClientMsgType_Unrecognized = 2, // Unrecognized request
k_EMsgGCCStrike15_v2_GC2ClientMsgType_BadPayload = 3, // Request was recognized, but payload was bad
k_EMsgGCCStrike15_v2_GC2ClientMsgType_ExecutionError = 4, // Request was not executed
k_EMsgGCCStrike15_v2_GC2ClientMsgType_PrintTextWarning = 5, // Response is warning text to be displayed to client
k_EMsgGCCStrike15_v2_GC2ClientMsgType_PrintTextInfo = 6, // Response is informational text to be displayed to client
k_EMsgGCCStrike15_v2_GC2ClientMsgType_WriteFile = 7, // Response is potentially binary payload to be written to response file
};
//=============================================================================
enum EMsgGCCStrike15_v2_GC2ClientNoteType
{
k_EMsgGCCStrike15_v2_GC2ClientNoteType_None = 0, // Nothing
k_EMsgGCCStrike15_v2_GC2ClientNoteType_ClusterLoadHigh = 1, // Datacenter has high load
k_EMsgGCCStrike15_v2_GC2ClientNoteType_ClusterOffline = 2, // Datacenter is offline
};
//=============================================================================
//=============================================================================
enum EMsgGCAccountPrivacySettingsType_t
{
//
// WARNING: These constants CANNOT be renumbered as they are stored in SQL!
//
k_EMsgGCAccountPrivacySettingsType_PlayerProfile = 1, // Player profile including competitive information and commendations
//
// WARNING: These constants CANNOT be renumbered as they are stored in SQL!
//
};
enum EMsgGCAccountPrivacySettingsValue_t
{
//
// WARNING: These constants CANNOT be renumbered as they are stored in SQL!
//
k_EMsgGCAccountPrivacySettingsValue_Default = 1, // Setting should be reset to default for the player
k_EMsgGCAccountPrivacySettingsValue_Disabled = 2, // Setting should be disabled
k_EMsgGCAccountPrivacySettingsValue_Enabled = 3, // Setting should be enabled
//
// WARNING: These constants CANNOT be renumbered as they are stored in SQL!
//
};
inline bool EMsgGCAccountPrivacySettingsType_IsExposedToClient( EMsgGCAccountPrivacySettingsType_t val )
{
return ( val == k_EMsgGCAccountPrivacySettingsType_PlayerProfile );
}
//=============================================================================
enum EMsgGCAccountPrivacyRequestLevel_t
{
//
// WARNING: These constants are used in protobuf communication and cannot renumber if used in same proto field!
//
k_EMsgGCAccountPrivacySettingsValue_Public_All = 0, // Requesting data that is already easily available to everybody (e.g. persona name)
k_EMsgGCAccountPrivacySettingsValue_Public_Shared = 0x10, // Setting can be shared with public
k_EMsgGCAccountPrivacySettingsValue_Friends_Only = 0x20, // Setting shared with friends
k_EMsgGCAccountPrivacySettingsValue_Private_All = 0x80, // All information that should already be available to the owner
//
// WARNING: These constants are used in protobuf communication and cannot renumber if used in same proto field!
//
};
//=============================================================================
enum EMsgGCVarValueNotificationInfoType_t
{
//
// WARNING: These constants are used in protobuf communication and cannot renumber if used in same proto field!
//
k_EMsgGCVarValueNotificationInfoType_Cmd = 0, // Data from user cmd
k_EMsgGCVarValueNotificationInfoType_Divergence = 1, // Divergence of viewangles
k_EMsgGCVarValueNotificationInfoType_Inventory = 2, // Community server misrepresenting inventory or rank
//
// WARNING: These constants are used in protobuf communication and cannot renumber if used in same proto field!
//
};
//=============================================================================
enum EMsgGCCStrike15_v2_NqmmRating_t
{
k_EMsgGCCStrike15_v2_NqmmRating_Version_Current = 1, // Current version of nqmm rating serialization
};
//=============================================================================
enum EScoreLeaderboardDataEntryTag_t
{
//
// WARNING: These constants CANNOT be renumbered as they are stored in SQL!
//
k_EScoreLeaderboardDataEntryTag_undefined = 0,
k_EScoreLeaderboardDataEntryTag_Kills = 1,
k_EScoreLeaderboardDataEntryTag_Assists = 2,
k_EScoreLeaderboardDataEntryTag_Deaths = 3,
k_EScoreLeaderboardDataEntryTag_Points = 4,
k_EScoreLeaderboardDataEntryTag_Headshots = 5,
k_EScoreLeaderboardDataEntryTag_ShotsFired = 6,
k_EScoreLeaderboardDataEntryTag_ShotsOnTarget = 7,
k_EScoreLeaderboardDataEntryTag_HpDmgInflicted = 8,
k_EScoreLeaderboardDataEntryTag_HpDmgSuffered = 9,
k_EScoreLeaderboardDataEntryTag_TimeElapsed = 10,
k_EScoreLeaderboardDataEntryTag_TimeRemaining = 11,
k_EScoreLeaderboardDataEntryTag_RoundsPlayed = 12,
k_EScoreLeaderboardDataEntryTag_BonusPistolOnly = 13,
k_EScoreLeaderboardDataEntryTag_BonusHardMode = 14,
k_EScoreLeaderboardDataEntryTag_BonusChallenge = 15,
//
// WARNING: These constants CANNOT be renumbered as they are stored in SQL!
//
};
//=============================================================================
#endif //CSTRIKE15_GCCONSTANTS_H
@@ -0,0 +1,34 @@
//====== Copyright (C), Valve Corporation, All rights reserved. =======
//
// Purpose: This file defines all of our mapgroups that can be selected on
// the client for GC-matchmaking and server would map these mapgroups
// to the corresponding mapgroup of gamemodes.txt
//
//=============================================================================
MAPGROUPENUM( de_dust )
MAPGROUPENUM( de_dust2 )
MAPGROUPENUM( de_train )
MAPGROUPENUM( de_aztec )
MAPGROUPENUM( de_inferno )
MAPGROUPENUM( de_nuke )
MAPGROUPENUM( de_vertigo )
MAPGROUPENUM( de_mirage )
MAPGROUPENUM( cs_office )
MAPGROUPENUM( cs_italy )
MAPGROUPENUM( cs_assault )
MAPGROUPENUM( cs_militia )
MAPGROUPENUM( de_cache )
MAPGROUPENUM( de_overpass )
MAPGROUPENUM( de_cbble )
MAPGROUPENUM( de_canals )
MAPGROUPENUM( cs_cruise )
MAPGROUPENUM( de_coast )
MAPGROUPENUM( de_empire )
MAPGROUPENUM( de_mikla )
MAPGROUPENUM( de_royal )
MAPGROUPENUM( de_santorini )
MAPGROUPENUM( de_tulip )
@@ -0,0 +1,14 @@
//====== Copyright (C), Valve Corporation, All rights reserved. =======
//
// Purpose: This file defines all of our mapgroups that can be selected on
// the client for GC-matchmaking and server would map these mapgroups
// to the corresponding mapgroup of gamemodes.txt
//
//=============================================================================
MAPGROUPENUM( ar_shoots )
MAPGROUPENUM( ar_baggage )
MAPGROUPENUM( ar_monastery )
MAPGROUPENUM( de_lake )
MAPGROUPENUM( de_stmarc )
MAPGROUPENUM( de_safehouse )
@@ -0,0 +1,13 @@
//====== Copyright (C), Valve Corporation, All rights reserved. =======
//
// Purpose: This file defines all of our mapgroups that can be selected on
// the client for GC-matchmaking and server would map these mapgroups
// to the corresponding mapgroup of gamemodes.txt
//
//=============================================================================
MAPGROUPENUM( active )
MAPGROUPENUM( dust247 )
MAPGROUPENUM( reserves )
MAPGROUPENUM( hostage )
MAPGROUPENUM( op_op07 )
@@ -0,0 +1,15 @@
//====== Copyright (C), Valve Corporation, All rights reserved. =======
//
// Purpose: This file defines all of our mapgroups that can be selected on
// the client for GC-matchmaking and server would map these mapgroups
// to the corresponding mapgroup of gamemodes.txt
//
//=============================================================================
MAPGROUPENUM( de_bank )
MAPGROUPENUM( de_shorttrain )
MAPGROUPENUM( de_sugarcane )
MAPGROUPENUM( de_lake )
MAPGROUPENUM( de_stmarc )
MAPGROUPENUM( de_safehouse )
MAPGROUPENUM( de_shortdust )
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,24 @@
$MacroRequired PROTOBUF_BUILDER_INCLUDED
$Project
{
$Folder "Protobuf Files"
{
$File "$SRCDIR\game\shared\cstrike15\cstrike15_gcmessages.proto" \
"$SRCDIR\common\engine_gcmessages.proto"
$DynamicFile "$GENERATED_PROTO_DIR\cstrike15_gcmessages.pb.h" \
"$GENERATED_PROTO_DIR\engine_gcmessages.pb.h"
$DynamicFile "$GENERATED_PROTO_DIR\cstrike15_gcmessages.pb.cc" \
"$GENERATED_PROTO_DIR\engine_gcmessages.pb.cc"
{
$Configuration
{
$Compiler [$WINDOWS]
{
$Create/UsePrecompiledHeader "Not Using Precompiled Headers"
}
}
}
}
}
@@ -0,0 +1,304 @@
//====== Copyright 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#ifndef CSTRIKE15_ITEM_CONSTANTS_H
#define CSTRIKE15_ITEM_CONSTANTS_H
#ifdef _WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// Purpose: Slots for items within loadouts
// NOTE: Explicitly numbered slots are for shipped features with the number saved in the database, do not renumber.
// Some legacy entries in the enum are still here and some game code uses them, but are not yet shipped and would be
// safe to renumber or remove if needed
//-----------------------------------------------------------------------------
enum loadout_positions_t
{
LOADOUT_POSITION_INVALID = -1,
LOADOUT_POSITION_MELEE = 0,
LOADOUT_POSITION_C4 = 1,
LOADOUT_POSITION_FIRST_AUTO_BUY_WEAPON = LOADOUT_POSITION_MELEE,
LOADOUT_POSITION_LAST_AUTO_BUY_WEAPON = LOADOUT_POSITION_C4,
LOADOUT_POSITION_SECONDARY0 = 2,
LOADOUT_POSITION_SECONDARY1 = 3,
LOADOUT_POSITION_SECONDARY2 = 4,
LOADOUT_POSITION_SECONDARY3 = 5,
LOADOUT_POSITION_SECONDARY4 = 6,
LOADOUT_POSITION_SECONDARY5 = 7, // Unused, no instances in database yet
LOADOUT_POSITION_SMG0 = 8,
LOADOUT_POSITION_SMG1 = 9,
LOADOUT_POSITION_SMG2 = 10,
LOADOUT_POSITION_SMG3 = 11,
LOADOUT_POSITION_SMG4 = 12,
LOADOUT_POSITION_SMG5 = 13, // Unused, no instances in database yet
LOADOUT_POSITION_RIFLE0 = 14,
LOADOUT_POSITION_RIFLE1 = 15,
LOADOUT_POSITION_RIFLE2 = 16,
LOADOUT_POSITION_RIFLE3 = 17,
LOADOUT_POSITION_RIFLE4 = 18,
LOADOUT_POSITION_RIFLE5 = 19,
LOADOUT_POSITION_HEAVY0 = 20,
LOADOUT_POSITION_HEAVY1 = 21,
LOADOUT_POSITION_HEAVY2 = 22,
LOADOUT_POSITION_HEAVY3 = 23,
LOADOUT_POSITION_HEAVY4 = 24,
LOADOUT_POSITION_HEAVY5 = 25, // Unused, no instances in database yet
LOADOUT_POSITION_FIRST_WHEEL_WEAPON = LOADOUT_POSITION_SECONDARY0,
LOADOUT_POSITION_LAST_WHEEL_WEAPON = LOADOUT_POSITION_HEAVY5,
// Grenade slots not yet saved in db
LOADOUT_POSITION_FIRST_WHEEL_GRENADE,
LOADOUT_POSITION_GRENADE0 = LOADOUT_POSITION_FIRST_WHEEL_GRENADE,
LOADOUT_POSITION_GRENADE1,
LOADOUT_POSITION_GRENADE2,
LOADOUT_POSITION_GRENADE3,
LOADOUT_POSITION_GRENADE4,
LOADOUT_POSITION_GRENADE5,
LOADOUT_POSITION_LAST_WHEEL_GRENADE = LOADOUT_POSITION_GRENADE5,
// Equipment slots not yet saved in db
LOADOUT_POSITION_EQUIPMENT0,
LOADOUT_POSITION_EQUIPMENT1,
LOADOUT_POSITION_EQUIPMENT2,
LOADOUT_POSITION_EQUIPMENT3,
LOADOUT_POSITION_EQUIPMENT4,
LOADOUT_POSITION_EQUIPMENT5,
LOADOUT_POSITION_FIRST_WHEEL_EQUIPMENT = LOADOUT_POSITION_EQUIPMENT0,
LOADOUT_POSITION_LAST_WHEEL_EQUIPMENT = LOADOUT_POSITION_EQUIPMENT5,
// Only glove slot saved in db
LOADOUT_POSITION_CLOTHING_APPEARANCE,
LOADOUT_POSITION_CLOTHING_TORSO,
LOADOUT_POSITION_CLOTHING_LOWERBODY,
LOADOUT_POSITION_CLOTHING_HANDS = 41, // ALREADY SHIPPED, idx must == 41
LOADOUT_POSITION_CLOTHING_HAT,
LOADOUT_POSITION_CLOTHING_FACEMASK,
LOADOUT_POSITION_CLOTHING_EYEWEAR,
LOADOUT_POSITION_CLOTHING_CUSTOMHEAD,
LOADOUT_POSITION_CLOTHING_CUSTOMPLAYER,
LOADOUT_POSITION_MISC0,
LOADOUT_POSITION_MISC1,
LOADOUT_POSITION_MISC2,
LOADOUT_POSITION_MISC3,
LOADOUT_POSITION_MISC4,
LOADOUT_POSITION_MISC5,
LOADOUT_POSITION_MISC6,
LOADOUT_POSITION_FIRST_COSMETIC = LOADOUT_POSITION_CLOTHING_APPEARANCE,
LOADOUT_POSITION_LAST_COSMETIC = LOADOUT_POSITION_MISC6,
// ^^^ Warning: CLOTHING COSEMTIC amount of enum entries doesn't match released enum, so must be shuffled before shipping to match public SQL!
LOADOUT_POSITION_MUSICKIT = 54,
LOADOUT_POSITION_FLAIR0 = 55,
LOADOUT_POSITION_SPRAY0 = 56,
LOADOUT_POSITION_FIRST_ALL_CHARACTER = LOADOUT_POSITION_MUSICKIT,
LOADOUT_POSITION_LAST_ALL_CHARACTER = LOADOUT_POSITION_SPRAY0,
LOADOUT_POSITION_COUNT,
};
#define LOADOUT_POSITION_NUM_AUTOBUY_WEAPONS ( ( LOADOUT_POSITION_LAST_AUTO_BUY_WEAPON - LOADOUT_POSITION_FIRST_AUTO_BUY_WEAPON) + 1 )
#define LOADOUT_POSITION_NUM_COSMETICS ( ( LOADOUT_POSITION_LAST_COSMETIC - LOADOUT_POSITION_FIRST_COSMETIC ) + 1 )
#define LOADOUT_POSITION_NUM_WHEEL_WEAPONS ( ( LOADOUT_POSITION_LAST_WHEEL_WEAPON - LOADOUT_POSITION_FIRST_WHEEL_WEAPON ) + 1 )
#define LOADOUT_POSITION_NUM_WHEEL_GRENADE ( ( LOADOUT_POSITION_LAST_WHEEL_GRENADE - LOADOUT_POSITION_FIRST_WHEEL_GRENADE ) + 1 )
#define LOADOUT_POSITION_NUM_WHEEL_EQUIPMENT ( ( LOADOUT_POSITION_LAST_WHEEL_EQUIPMENT - LOADOUT_POSITION_FIRST_WHEEL_EQUIPMENT ) + 1 )
#define LOADOUT_POSITION_NUM_ALL_CHARACTER ( ( LOADOUT_POSITION_LAST_ALL_CHARACTER - LOADOUT_POSITION_FIRST_ALL_CHARACTER ) + 1 )
#define LOADOUT_NUM_PANELS ( LOADOUT_POSITION_NUM_AUTOBUY_WEAPONS + LOADOUT_POSITION_NUM_COSMETICS + LOADOUT_POSITION_NUM_WHEEL_WEAPONS + LOADOUT_POSITION_NUM_ALL_CHARACTER )
// We use this to determine the maximum number of wearable instances we'll send from the server down to connected clients.
// This hardcoded because of the way RecvPropUtlVector works we can't easily change this
// without doing some kludgy work and breaking network/demo compatibility.
// Make sure this is up to date before shipping with enough overhead and don't change it without serious consideration.
#define LOADOUT_MAX_WEARABLES_COUNT ( 1 /*LOADOUT_POSITION_NUM_COSMETICS*/ )
inline bool IsWearableSlot( int iSlot )
{
return ( iSlot >= LOADOUT_POSITION_FIRST_COSMETIC && iSlot <= LOADOUT_POSITION_LAST_COSMETIC );
}
inline bool SlotContainsBaseItems( int iSlot )
{
// Primary wheel 2 has 6 base item slots... all the rest have 5 and one empty
if ( iSlot < LOADOUT_POSITION_MELEE )
{
return false;
}
if ( iSlot >= LOADOUT_POSITION_FIRST_WHEEL_WEAPON && iSlot <= LOADOUT_POSITION_LAST_WHEEL_WEAPON )
{
switch( iSlot )
{
case LOADOUT_POSITION_SECONDARY5:
case LOADOUT_POSITION_SMG5:
case LOADOUT_POSITION_HEAVY5:
return false;
}
return true;
}
if ( iSlot >= LOADOUT_POSITION_FIRST_WHEEL_GRENADE && iSlot <= LOADOUT_POSITION_LAST_WHEEL_GRENADE )
{
// switch( iSlot )
// {
// case LOADOUT_POSITION_GRENADE5:
// return false;
// }
return true;
}
if ( iSlot >= LOADOUT_POSITION_FIRST_WHEEL_EQUIPMENT && iSlot <= LOADOUT_POSITION_LAST_WHEEL_EQUIPMENT )
{
switch( iSlot )
{
case LOADOUT_POSITION_EQUIPMENT0:
case LOADOUT_POSITION_EQUIPMENT1:
case LOADOUT_POSITION_EQUIPMENT3:
case LOADOUT_POSITION_EQUIPMENT4:
case LOADOUT_POSITION_EQUIPMENT5:
return false;
}
return true;
}
if ( iSlot >= LOADOUT_POSITION_FIRST_COSMETIC && iSlot <= LOADOUT_POSITION_LAST_COSMETIC )
{
switch( iSlot )
{
case LOADOUT_POSITION_CLOTHING_APPEARANCE:
case LOADOUT_POSITION_CLOTHING_TORSO:
case LOADOUT_POSITION_CLOTHING_LOWERBODY:
case LOADOUT_POSITION_CLOTHING_HANDS:
case LOADOUT_POSITION_CLOTHING_HAT:
case LOADOUT_POSITION_CLOTHING_FACEMASK:
case LOADOUT_POSITION_CLOTHING_EYEWEAR:
case LOADOUT_POSITION_CLOTHING_CUSTOMHEAD:
case LOADOUT_POSITION_CLOTHING_CUSTOMPLAYER:
return true;
}
return false;
}
if ( iSlot == LOADOUT_POSITION_MUSICKIT )
return true;
if ( iSlot >= LOADOUT_POSITION_FIRST_ALL_CHARACTER && iSlot <= LOADOUT_POSITION_LAST_ALL_CHARACTER )
{
return false;
}
return true;
}
// The total number of loadouts to track for each player.
#define LOADOUT_COUNT (2+2) // these are the number of skins (2 valid + 2 invalid)
//-----------------------------------------------------------------------------
// The maximum number of presets per class - CS doesn't actually use all 10
// right now, though.
//-----------------------------------------------------------------------------
#define MAX_LOADOUT_PRESET_COUNT 10
enum xp_category_t
{
kXPCategory_None = 0,
kXPCategory_ContributionScore = 1, // Server can send ContributionScore (mutually exclusive with CompetitiveRoundWins)
kXPCategory_CompetitiveRoundWins = 2, // Server can send CompetitiveRoundWins (mutually exclusive with ContributionScore)
kXPCategory_BonusBoost = 3, // GC rewards this weekly boost
kXPCategory_Overwatch = 4, // GC rewards Overwatch XP in post SQL-transaction
kXPCategory_OverwatchBonusBoost = 5, // GC rewards Overwatch Bonus XP in post SQL-transaction
kXPCategory_QuestReward = 6, // Server sends evaluated quest points, and GC rewards Quest XP from coin progress
kXPCategory_QuestBonus = 7, // Server sends evaluated quest bonus points, and GC rewards Quest XP from coin progress
kXPCategory_QuestEvent = 8, // Server sends quest event XP, GC relays it to client
// kXPCategory_Headshots, etc
// GC can also use reduced XP reasons -
kXPCategory_ContributionScoreReduced = 51, // ContributionScore remapped by GC for client display
kXPCategory_CompetitiveRoundWinsReduced = 52, // CompetitiveRoundWins remapped by GC for client display
kXPCategory_OverwatchReduced = 54, // Overwatch XP reason remapped by GC for client display
kXPCategory_QuestEventReduced = 58, // QuestEvent XP reason remapped by GC for client display
// GC can also use introductory XP reasons -
kXPCategory_ContributionScoreIntroductory = 81, // ContributionScore remapped by GC for client display
kXPCategory_CompetitiveRoundWinsIntroductory = 82, // CompetitiveRoundWins remapped by GC for client display
kXPCategory_QuestEventIntroductory = 88, // QuestEvent XP reason remapped by GC for client display
// NEW ENTRIES MUST BE ADDED AT THE BOTTOM
};
const uint32 k_nCSGOXpPerLevel = 5000;
const uint32 k_nCSGOXpMaxLevel = 40;
// Prime status
const uint32 k_nCSGOMinLevelForPrimeStatus = 21;
inline uint32 CSGOXpPointsToLevel( uint32 unExperiencePoints ) { return Min( k_nCSGOXpMaxLevel, 1 + ( unExperiencePoints / k_nCSGOXpPerLevel ) ); }
inline uint32 CSGOXpPointsToXpPoints( uint32 unExperiencePoints ) { return unExperiencePoints % k_nCSGOXpPerLevel; }
inline uint32 CSGOXpPointsToXpWirePoints( uint32 unExperiencePoints )
{
COMPILE_TIME_ASSERT( k_nCSGOXpPerLevel < 0xFFFF );
Assert( unExperiencePoints <= 0xFFFF );
return ( ( unExperiencePoints ) & 0xFFFF ) | ( ( k_nCSGOXpPerLevel & 0xFFFF ) << 16 );
}
inline uint32 CSGOXpPointsFromXpWirePoints( uint32 unXpWirePoints )
{
COMPILE_TIME_ASSERT( k_nCSGOXpPerLevel < 0xFFFF );
uint32 const unWireBase = ( unXpWirePoints >> 16 ) & 0xFFFF;
if ( !unWireBase || ( unWireBase == k_nCSGOXpPerLevel ) )
return unXpWirePoints & 0xFFFF;
else
return uint32( ( double( unXpWirePoints & 0xFFFF ) / double( unWireBase ) ) * double( k_nCSGOXpPerLevel ) );
}
// STORED IN DATABASE! Do not renumber
enum
{
kCSXpBonusFlags_EarnedXpThisPeriod = 1 << 0,
kCSXpBonusFlags_FirstReward = 1 << 1,
kCSXpBonusFlags_Msg_YourReportGotConvicted = 1 << 2,
kCSXpBonusFlags_Msg_YouPartiedWithCheaters = 1 << 3,
kCSXpBonusFlags_PrestigeEarned = 1 << 4,
// ===$CHINAGOVERNMENTCERT$===
kCSXpBonusFlags_ChinaGovernmentCert = 1 << 5,
// ===$CHINAGOVERNMENTCERT$===
// Client-facing bits not backed by SQL
kCSXpBonusFlags_OverwatchBonus = 1 << 28,
kCSXpBonusFlags_BonusBoostConsumed = 1 << 29,
kCSXpBonusFlags_ReducedGain = 1 << 30,
kCSXpBonusFlagsMask_SQLBacked_TimeBased = ( kCSXpBonusFlags_EarnedXpThisPeriod | kCSXpBonusFlags_FirstReward ),
kCSXpBonusFlagsMask_SQLBacked_Notifications = ( kCSXpBonusFlags_Msg_YourReportGotConvicted | kCSXpBonusFlags_Msg_YouPartiedWithCheaters ),
kCSXpBonusFlagsMask_SQLBacked_Permanent = ( kCSXpBonusFlagsMask_SQLBacked_Notifications | kCSXpBonusFlags_PrestigeEarned
| kCSXpBonusFlags_ChinaGovernmentCert // ===$CHINAGOVERNMENTCERT$===
),
kCSXpBonusFlagsMask_SQLBacked = ( kCSXpBonusFlagsMask_SQLBacked_TimeBased | kCSXpBonusFlagsMask_SQLBacked_Permanent ),
kCSXpBonusFlagsMask_Client_Permanent = ( kCSXpBonusFlags_OverwatchBonus ),
kCSXpBonusFlagsMask_Client_TimeBased = ( kCSXpBonusFlags_BonusBoostConsumed | kCSXpBonusFlags_ReducedGain ),
};
// Used in scoreboard to show other players the reason for the drop. Standard weekly drops are of type 'None'.
enum
{
kCSGODropReason_None = 0,
kCSGODropReason_Quest = 1,
kCSGODropReason_LevelUp = 2,
};
#endif // CSTRIKE15_ITEM_CONSTANTS_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,206 @@
//====== Copyright © Valve Corporation, All rights reserved. =======
//
// Purpose: Container that allows client & server access to data in player inventories & loadouts
//
//=============================================================================
#pragma once
#include "econ_item_inventory.h"
#include "shareddefs.h"
#include "cs_shareddefs.h"
#include "econ_item_constants.h"
#include "cstrike15_item_constants.h"
#define LOADOUT_SLOT_USE_BASE_ITEM 0
namespace vgui
{
class Panel;
}
struct baseitemcriteria_t;
//===============================================================================================================
//-----------------------------------------------------------------------------
// Purpose: A single player's inventory.
// On the client, the inventory manager contains contains an instance of this for the local player.
// On the server, each player contains an instance of this.
//-----------------------------------------------------------------------------
class CCSPlayerInventory : public CPlayerInventory
{
DECLARE_CLASS( CCSPlayerInventory, CPlayerInventory );
public:
CCSPlayerInventory();
virtual CEconItemView *GetItemInLoadout( int iClass, int iSlot ) const;
CEconItemView* GetItemInLoadoutFilteredByProhibition( int iClass, int iSlot ) const;
#ifdef CLIENT_DLL
// Removes any item in a loadout slot. If the slot has a base item,
// the player essentially returns to using that item.
// NOTE: This can fail if the player has no backpack space to contain the equipped item.
bool ClearLoadoutSlot( int iClass, int iSlot );
int GetLastCompletedNodeForCampaign( uint32 unCampaignID ) const;
#endif
virtual int GetMaxItemCount( void ) const;
virtual bool CanPurchaseItems( int iItemCount ) const;
virtual int GetPreviewItemDef( void ) const;
bool IsMissionRefuseAllowed( void ) const;
// Derived inventory hooks
virtual void ItemHasBeenUpdated( CEconItemView *pItem, bool bUpdateAckFile, bool bWriteAckFile, EInventoryItemEvent eEventType ) OVERRIDE;
virtual void ItemIsBeingRemoved( CEconItemView *pItem ) OVERRIDE;
virtual void DefaultEquippedDefinitionHasBeenUpdated( CEconDefaultEquippedDefinitionInstanceClient *pDefaultEquippedDefinition ) OVERRIDE;
// Debugging
virtual void DumpInventoryToConsole( bool bRoot );
virtual void NotifyHasNewItems() { OnHasNewItems(); }
public:
float FindInventoryItemWithMaxAttributeValue( char const *szItemType, char const *szAttrClass, CEconItemView **ppItemFound = NULL );
void FindInventoryItemsWithAttribute( char const *szAttrClass, CUtlVector< CEconItemView* > &foundItems, bool bMatchValue = false, uint32 unValue = 0 ); // DEPRECATED. Use CSchemaAttributeDefHandle version instead and use static handles.
void FindInventoryItemsWithAttribute( CSchemaAttributeDefHandle pAttr, CUtlVector< CEconItemView* > &foundItems, CUtlVector< CEconItemView* > *searchSet = NULL, bool bMatchValue = false, uint32 unValue = 0 );
itemid_t GetActiveSeasonItemId( bool bCoin = true /* false is the Pass */ );
uint32 GetActiveQuestID( void ) const;
void RefreshActiveQuestID( void );
bool IsEquipped( CEconItemView * pEconItem, int nTeam );
bool IsEquipped( CEconItemView * pEconItem );
protected:
#ifdef CLIENT_DLL
// Converts an old format inventory to the new format.
void ConvertOldFormatInventoryToNew( void );
#endif
int m_nActiveQuestID;
virtual void OnHasNewItems();
virtual void ValidateInventoryPositions( void );
virtual void SOCacheSubscribed( GCSDK::SOID_t owner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
// Extracts the position that should be used to sort items in the inventory from the backend position.
// Necessary if your inventory packs a bunch of info into the position instead of using it just as a position.
virtual int ExtractInventorySortPosition( uint32 iBackendPosition )
{
// Consider unack'd items as -1, so they get stacked up before the 0th slot item
if ( IsUnacknowledged(iBackendPosition) )
return -1;
return ExtractBackpackPositionFromBackend(iBackendPosition);
}
virtual void SOCreated( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void SOUpdated( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void SODestroyed( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
protected:
// Global indices of the items in our inventory in the loadout slots
itemid_t m_LoadoutItems[ LOADOUT_COUNT ][ LOADOUT_POSITION_COUNT ];
friend class CCSInventoryManager;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CCSInventoryManager : public CInventoryManager
{
DECLARE_CLASS( CCSInventoryManager, CInventoryManager );
public:
CCSInventoryManager();
virtual bool Init( void );
virtual void PostInit( void );
virtual void Shutdown( void );
virtual void LevelInitPreEntity( void ) OVERRIDE;
#ifdef CLIENT_DLL
virtual CPlayerInventory *GeneratePlayerInventoryObject() const { return new CCSPlayerInventory; }
// Get the number of items picked up
virtual int GetNumItemPickedUpItems( void );
// Show the player a pickup screen with any items they've collected recently, if any
virtual bool ShowItemsPickedUp( bool bForce = false, bool bReturnToGame = true, bool bNoPanel = false );
void UpdateUnacknowledgedItems( void );
void RebuildUnacknowledgedItemList( CUtlVector< CEconItemView* > *pVecItemsAckedOnClientOnly = NULL );
// Get list of unacknowledged items. Optionally will rebuild the list before returning.
CUtlVector<CEconItemView*> &GetUnacknowledgedItems( bool bRefreshList );
void AcknowledgeUnacknowledgedItems( void );
bool AcknowledgeUnacknowledgedItem( itemid_t ui64ItemID );
// Show the player a pickup screen with the items they've crafted
virtual void ShowItemsCrafted( CUtlVector<itemid_t> *vecCraftedIndices );
// Force the player to discard an item to make room for a new item, if they have one
virtual bool CheckForRoomAndForceDiscard( void );
#endif
// Does a mapping to a "class" index based on a class index and a preset index, so that presets can be stored in the GC.
virtual equipped_class_t DoClassMapping( equipped_class_t unClass, equipped_preset_t unPreset );
// Returns the item data for the base item in the loadout slot for a given class
CEconItemView *GetBaseItemForTeam( int iClass, int iSlot );
void GenerateBaseItems( void );
// Gets the specified inventory for the steam ID
CCSPlayerInventory *GetInventoryForPlayer( const CSteamID &playerID );
// Returns the item in the specified loadout slot for a given class
CEconItemView *GetItemInLoadoutForTeam( int iClass, int iSlot, CSteamID *pID = NULL );
int GetSlotForBaseOrDefaultEquipped( int iClass, item_definition_index_t );
// Fills out the vector with the sets that are currently active on the specified player & class
void GetActiveSets( CUtlVector<const CEconItemSetDefinition *> *pItemSets, CSteamID steamIDForPlayer, int iClass );
// We're generating a base item. We need to add the game-specific keys to the criteria so that it'll find the right base item.
virtual void AddBaseItemCriteria( baseitemcriteria_t *pCriteria, CItemSelectionCriteria *pSelectionCriteria );
private:
// Base items, returned for slots that the player doesn't have anything in
CEconItemView m_pBaseLoadoutItems[ LOADOUT_COUNT ][ LOADOUT_POSITION_COUNT ];
#ifdef CLIENT_DLL
// On the client, we have a single inventory for the local player. Stored here, instead of in the
// local player entity, because players need to access it while not being connected to a server.
public:
CPlayerInventory *GetLocalInventory( void ) { Assert( m_pLocalInventory ); return m_pLocalInventory; }
CCSPlayerInventory *GetLocalCSInventory( void ) { Assert( m_pLocalInventory ); return m_pLocalInventory; }
// Try and equip the specified item in the specified class's loadout slot
bool EquipItemInLoadout( int iClass, int iSlot, itemid_t iItemID, bool bSwap = false );
bool CleanupDuplicateBaseItems( int iClass );
// Fills out pList with all inventory items that could fit into the specified loadout slot for a given class
int GetAllUsableItemsForSlot( int iClass, int iSlot, unsigned int unUsedEquipRegionMask, CUtlVector<CEconItemView*> *pList );
virtual int GetBackpackPositionFromBackend( uint32 iBackendPosition ) { return ExtractBackpackPositionFromBackend(iBackendPosition); }
private:
CCSPlayerInventory *m_pLocalInventory;
CUtlVector<CEconItemView*> m_UnacknowledgedItems;
#endif // CLIENT_DLL
};
CCSInventoryManager *CSInventoryManager( void );
bool AreSlotsConsideredIdentical( int iBaseSlot, int iTestSlot );
@@ -0,0 +1,779 @@
//========= Copyright (c), Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "cstrike15_item_schema.h"
#include "game_item_schema.h"
#include "schemainitutils.h"
#include "shareddefs.h"
#include "cs_shareddefs.h"
#include "mathlib/lightdesc.h"
#ifndef GC_DLL
#include "econ_item_system.h"
#endif // !GC_DLL
const char CCStrike15ItemSchema::k_rchCommunitySupportPassItemDefName[] = "Community Season One Spring 2013";
//--------------------------------------------------------------------------------------------------
// Purpose: Constructor.
//--------------------------------------------------------------------------------------------------
CCStrike15ItemDefinition::CCStrike15ItemDefinition()
{
m_bIsSupplyCrate = false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CCStrike15ItemDefinition::BInitFromKV( KeyValues *pKVItem, CEconItemSchema &schemaa, CUtlVector<CUtlString> *pVecErrors )
{
CEconItemDefinition::BInitFromKV( pKVItem, schemaa, pVecErrors );
CCStrike15ItemSchema *pSchema = ItemSystem()->GetItemSchema();
// Get the default loadout slot
const char *pchSubPosition = GetRawDefinition()->GetString( "item_sub_position", NULL );
m_iDefaultLoadoutSlot = ( pchSubPosition ? StringFieldToInt( pchSubPosition, pSchema->GetLoadoutStringsSubPositions() ) : -1 );
for ( int i = 0; i < LOADOUT_COUNT; i++ )
{
m_iLoadoutSlots[i] = LOADOUT_POSITION_INVALID;
}
if ( m_iDefaultLoadoutSlot == LOADOUT_POSITION_CLOTHING_HANDS && !IsBaseItem() )
{
SCHEMA_INIT_CHECK( GetWorldDisplayModel(), CFmtStr( "Glove model %s (def idx %d) is missing world model key.", GetDefinitionName(), GetDefinitionIndex() ) );
}
// record if this item shares a loadout position with another type of item (m4, cz/p250)
m_bItemSharesEquipSlot = GetRawDefinition()->GetBool( "item_shares_equip_slot" );
const char *pchItemClass = GetItemClass();
SCHEMA_INIT_CHECK( pchItemClass, CFmtStr( "Item \"%s\" is missing schema item class!", pKVItem->GetName() ) );
m_bIsSupplyCrate = ( pchItemClass && !V_strcmp( pchItemClass, "supply_crate" ) );
// Class usability--use our copy of kv item
KeyValues *pClasses = GetRawDefinition()->FindKey( "used_by_classes" );
if ( pClasses )
{
m_vbClassUsability.ClearAll();
KeyValues *pKVClass = pClasses->GetFirstSubKey();
while ( pKVClass )
{
int iTeam = StringFieldToInt( pKVClass->GetName(), pSchema->GetClassUsabilityStrings() );
if ( iTeam > -1 )
{
m_vbClassUsability.Set(iTeam);
m_iLoadoutSlots[iTeam] = m_iDefaultLoadoutSlot;
// If the value is "1", the class uses this item in the default loadout slot.
const char *pszValue = pKVClass->GetString();
if ( pszValue[0] != '1' )
{
int iSlot = StringFieldToInt( pszValue, pSchema->GetLoadoutStrings() );
Assert( iSlot != -1 );
if ( iSlot != -1 )
{
m_iLoadoutSlots[iTeam] = iSlot;
}
}
}
pKVClass = pKVClass->GetNextKey();
}
// add "all_class" if applicable
if ( CanBeUsedByAllTeams() )
{
KeyValues *pKVAllClassKey = new KeyValues( "all_class", "all_class", "1" );
pClasses->AddSubKey( pKVAllClassKey );
}
}
// Verify that no items are set up to be equipped in a wearable slot for some classes and a
// non-wearable slot other times. "Is this in a wearable slot?" is used to determine whether
// or not content can be allowed to stream, so we don't allow an item to overlap.
bool bHasAnyWearableSlots = false,
bHasAnyNonwearableSlots = false;
for ( int i = 0; i < LOADOUT_COUNT; i++ )
{
if ( m_iLoadoutSlots[i] != LOADOUT_POSITION_INVALID )
{
const bool bThisIsWearableSlot = IsWearableSlot( m_iLoadoutSlots[i] );
(bThisIsWearableSlot ? bHasAnyWearableSlots : bHasAnyNonwearableSlots) = true;
}
}
SCHEMA_INIT_CHECK(
!(bHasAnyWearableSlots && bHasAnyNonwearableSlots),
CFmtStr( "Item definition %i \"%s\" used in both wearable and not wearable slots!", GetDefinitionIndex(), GetItemBaseName() ) );
// "anim_slot"
m_iAnimationSlot = -1;
const char *pszAnimSlot = GetRawDefinition()->GetString("anim_slot");
if ( pszAnimSlot && pszAnimSlot[0] )
{
if ( Q_stricmp(pszAnimSlot, "FORCE_NOT_USED") == 0 )
{
m_iAnimationSlot = -2;
}
else
{
m_iAnimationSlot = StringFieldToInt( pszAnimSlot, pSchema->GetWeaponTypeSubstrings() );
}
}
// Initialize player display model.
for ( int i = 0; i < LOADOUT_COUNT; i++ )
{
m_pszPlayerDisplayModel[i] = NULL;
}
// "model_player_per_class"
KeyValues *pPerClassModels = GetRawDefinition()->FindKey( "model_player_per_class" );
for ( int i = 1; i < LOADOUT_COUNT; i++ )
{
if ( pPerClassModels )
{
m_pszPlayerDisplayModel[i] = pPerClassModels->GetString( pSchema->GetClassUsabilityStrings()[i], NULL );
if ( m_pszPlayerDisplayModel[0] == NULL )
{
m_pszPlayerDisplayModel[0] = m_pszPlayerDisplayModel[i];
}
}
}
// Stomp duplicate properties.
if ( !m_pszPlayerDisplayModel[0] )
{
m_pszPlayerDisplayModel[0] = GetBasePlayerDisplayModel();
}
// parse Paint Data
KeyValues *pPaintData = GetRawDefinition()->FindKey( "paint_data" );
if ( pPaintData )
{
KeyValues *pPaintableMaterialKeys = pPaintData->GetFirstSubKey();
while ( pPaintableMaterialKeys )
{
const char *pName = pPaintableMaterialKeys->GetString( "Name" );
if ( pName[0] != 0 )
{
WeaponPaintableMaterial_t *pPaintableMaterial = &m_PaintData[ m_PaintData.AddToTail() ];
V_strncpy( pPaintableMaterial->m_szName, pName, sizeof( pPaintableMaterial->m_szName ) );
const char *pOriginalMaterialName = pPaintableMaterialKeys->GetString( "OrigMat", "" );
V_strncpy( pPaintableMaterial->m_szOriginalMaterialName, pOriginalMaterialName, sizeof( pPaintableMaterial->m_szOriginalMaterialName ) );
const char *pFolderName = pPaintableMaterialKeys->GetString( "FolderName", pPaintableMaterial->m_szName ); // defaults to same as the name
V_strncpy( pPaintableMaterial->m_szFolderName, pFolderName, sizeof( pPaintableMaterial->m_szFolderName ) );
pPaintableMaterial->m_nViewModelSize = pPaintableMaterialKeys->GetInt( "ViewmodelDim", 1024 );
pPaintableMaterial->m_nWorldModelSize = pPaintableMaterialKeys->GetInt( "WorldDim", 512 );
pPaintableMaterial->m_flWeaponLength = pPaintableMaterialKeys->GetFloat( "WeaponLength", 36.0f );
pPaintableMaterial->m_flUVScale = pPaintableMaterialKeys->GetFloat( "UVScale", 1.0f );
pPaintableMaterial->m_bBaseTextureOverride = pPaintableMaterialKeys->GetBool( "BaseTextureOverride" );
pPaintableMaterial->m_bMirrorPattern = pPaintableMaterialKeys->GetBool( "MirrorPattern", false );
}
else
{
DevMsg( "Error Parsing PaintData in %s! \n", GetDefinitionName() );
}
pPaintableMaterialKeys = pPaintableMaterialKeys->GetNextKey();
}
}
// parse inventory image data
KeyValues *pInventoryImageData = GetRawDefinition()->FindKey( "inventory_image_data" );
if ( pInventoryImageData )
{
m_pInventoryImageData = new InventoryImageData_t;
m_pInventoryImageData->m_pCameraAngles = NULL;
m_pInventoryImageData->m_pCameraOffset = NULL;
m_pInventoryImageData->m_cameraFOV = -1.0f;
for ( int i = 0; i < MATERIAL_MAX_LIGHT_COUNT; i++ )
{
m_pInventoryImageData->m_pLightDesc[ i ] = NULL;
}
m_pInventoryImageData->m_bOverrideDefaultLight = pInventoryImageData->GetBool( "override_default_light", false );
const char *pCameraAngles = pInventoryImageData->GetString( "camera_angles" );
if ( pCameraAngles[0] != 0 )
{
float flX = 0.0f, flY = 0.0f, flZ = 0.0f;
sscanf( pCameraAngles, "%f %f %f", &flX, &flY, &flZ );
m_pInventoryImageData->m_pCameraAngles = new QAngle( flX, flY, flZ );
}
const char *pCameraOffset = pInventoryImageData->GetString( "camera_offset" );
if ( pCameraOffset[0] != 0 )
{
float flX = 0.0f, flY = 0.0f, flZ = 0.0f;
sscanf( pCameraOffset, "%f %f %f", &flX, &flY, &flZ );
m_pInventoryImageData->m_pCameraOffset = new Vector( flX, flY, flZ );
}
m_pInventoryImageData->m_cameraFOV = pInventoryImageData->GetFloat( "camera_fov", -1.0f );
int nNumLightDescs = 0;
KeyValues *pLightKeys = pInventoryImageData->GetFirstTrueSubKey();
while ( pLightKeys )
{
if ( nNumLightDescs >= ( MATERIAL_MAX_LIGHT_COUNT - ( ( m_pInventoryImageData->m_bOverrideDefaultLight ) ? 0 : 1 ) ) )
{
DevMsg( "Too many lights defined in inventory_image_data in %s. Only using first %d. \n", GetDefinitionName(), MATERIAL_MAX_LIGHT_COUNT );
break;
}
const char *pLightType = pLightKeys->GetName();
if ( pLightType[0] != 0 )
{
LightType_t lightType = MATERIAL_LIGHT_DISABLE;
if ( V_strnicmp( pLightType, "point_light", 11 ) == 0 )
{
lightType = MATERIAL_LIGHT_POINT;
}
else if ( V_strnicmp( pLightType, "directional_light", 17 ) == 0 )
{
lightType = MATERIAL_LIGHT_DIRECTIONAL;
}
else if ( V_strnicmp( pLightType, "spot_light", 10 ) == 0 )
{
lightType = MATERIAL_LIGHT_SPOT;
}
else
{
DevMsg( "Error Parsing inventory_image_data in %s! Unknown light type %s. \n", GetDefinitionName(), pLightType );
}
if ( lightType != MATERIAL_LIGHT_DISABLE )
{
Vector lightPosOrDir( 0, 0, 0 );
Vector lightColor( 0, 0, 0 );
const char *pLightPosOrDir = pLightKeys->GetString( ( lightType == MATERIAL_LIGHT_DIRECTIONAL ) ? "direction" : "position" );
if ( pLightPosOrDir[0] != 0 )
{
sscanf( pLightPosOrDir, "%f %f %f", &(lightPosOrDir.x), &(lightPosOrDir.y), &(lightPosOrDir.z) );
}
const char *pLightColor = pLightKeys->GetString( "color" );
if ( pLightColor[0] != 0 )
{
sscanf( pLightColor, "%f %f %f", &(lightColor.x), &(lightColor.y), &(lightColor.z) );
}
Vector lightLookAt( 0, 0, 0 );
float lightInnerCone = 1.0f;
float lightOuterCone = 10.0f;
if ( lightType == MATERIAL_LIGHT_SPOT )
{
const char *pLightLookAt = pLightKeys->GetString( "lookat" );
if ( pLightLookAt[0] != 0 )
{
sscanf( pLightLookAt, "%f %f %f", &(lightLookAt.x), &(lightLookAt.y), &(lightLookAt.z) );
}
lightInnerCone = pLightKeys->GetFloat( "inner_cone", 1.0f );
lightOuterCone = pLightKeys->GetFloat( "outer_cone", 8.0f );
}
m_pInventoryImageData->m_pLightDesc[ nNumLightDescs ] = new LightDesc_t;
switch ( lightType )
{
case MATERIAL_LIGHT_DIRECTIONAL:
m_pInventoryImageData->m_pLightDesc[ nNumLightDescs ]->InitDirectional( lightPosOrDir, lightColor );
break;
case MATERIAL_LIGHT_POINT:
m_pInventoryImageData->m_pLightDesc[ nNumLightDescs ]->InitPoint( lightPosOrDir, lightColor );
break;
case MATERIAL_LIGHT_SPOT:
m_pInventoryImageData->m_pLightDesc[ nNumLightDescs ]->InitSpot( lightPosOrDir, lightColor, lightLookAt, lightInnerCone, lightOuterCone );
break;
}
nNumLightDescs++;
}
}
pLightKeys = pLightKeys->GetNextTrueSubKey();
}
}
return SCHEMA_INIT_SUCCESS();
}
#ifndef GC_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CCStrike15ItemDefinition::BInitFromTestItemKVs( int iNewDefIndex, KeyValues *pKVItem, CEconItemSchema &schemaa )
{
if ( !CEconItemDefinition::BInitFromTestItemKVs( iNewDefIndex, pKVItem, schemaa ) )
return false;
// Use the tester's class usage choices, even when testing existing items
m_vbClassUsability.ClearAll();
int iTeamUsage = pKVItem->GetInt( "class_usage", 0 );
for ( int i = 0; i < LOADOUT_COUNT; i++ )
{
if ( iTeamUsage & (1 << i) || (iTeamUsage & 1) )
{
m_vbClassUsability.Set(i);
m_iLoadoutSlots[i] = m_iDefaultLoadoutSlot;
}
}
// Stomp duplicate properties.
m_pszPlayerDisplayModel[0] = GetBasePlayerDisplayModel();
return true;
}
#endif // !GC_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCStrike15ItemDefinition::CopyPolymorphic( const CEconItemDefinition *pSourceDef )
{
Assert( dynamic_cast<const CCStrike15ItemDefinition *>( pSourceDef ) != NULL );
*this = *(const CCStrike15ItemDefinition *)pSourceDef;
}
#ifndef GC_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCStrike15ItemDefinition::GeneratePrecacheModelStrings( bool bDynamicLoad, CUtlVector<const char *> *out_pVecModelStrings )
{
Assert( out_pVecModelStrings );
// Is this definition supposed to use dynamic-loaded content or precache it?
if ( !bDynamicLoad || !IsContentStreamable() )
{
// Parent class base meshes, if relevant.
CEconItemDefinition::GeneratePrecacheModelStrings( bDynamicLoad, out_pVecModelStrings );
// Per-class models.
for ( int i = 0; i < LOADOUT_COUNT; i++ )
{
const char *pszModel = GetPlayerDisplayModel(i);
if ( pszModel && pszModel[0] )
{
out_pVecModelStrings->AddToTail( pszModel );
}
}
const char *pszModel = GetWorldDisplayModel();
if ( pszModel && pszModel[0] )
{
out_pVecModelStrings->AddToTail( pszModel );
}
}
}
#endif // !GC_DLL
//-----------------------------------------------------------------------------
// Purpose: Return the load-out slot that this item must be placed into
//-----------------------------------------------------------------------------
int CCStrike15ItemDefinition::GetLoadoutSlot( int iTeam ) const
{
if ( iTeam <= 0 || iTeam >= LOADOUT_COUNT )
return m_iDefaultLoadoutSlot;
return m_iLoadoutSlots[iTeam];
}
#ifndef GC_DLL
//-----------------------------------------------------------------------------
// Purpose: Returns true if this item is in a wearable slot, or is acting as a wearable
//-----------------------------------------------------------------------------
bool CCStrike15ItemDefinition::IsAWearable( int iSlot ) const
{
if ( IsWearableSlot( iSlot ) )
return true;
if ( IsActingAsAWearable() )
return true;
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Returns true if the content for this item view should be streamed. If false,
// it should be preloaded.
//-----------------------------------------------------------------------------
#define ITEM_ENABLE_ITEM_CONTENT_STREAMING true
//ConVar item_enable_content_streaming( "item_enable_content_streaming", "1", FCVAR_ARCHIVE | FCVAR_DEVELOPMENTONLY );
bool CCStrike15ItemDefinition::IsContentStreamable() const
{
if ( !IsAWearable( GetDefaultLoadoutSlot() ) )
return false;
return ITEM_ENABLE_ITEM_CONTENT_STREAMING
&& CEconItemDefinition::IsContentStreamable();
}
#endif // !GC_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCStrike15ItemDefinition::FilloutSlotUsage( CBitVec<LOADOUT_COUNT> *pBV ) const
{
pBV->ClearAll();
for ( int i = 0; i < LOADOUT_COUNT; i++ )
{
if ( m_iLoadoutSlots[i] == LOADOUT_POSITION_INVALID )
continue;
pBV->Set( m_iLoadoutSlots[i] );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CCStrike15ItemDefinition::GetUsedByTeam( void ) const
{
if ( CanBeUsedByTeam(TEAM_TERRORIST) && CanBeUsedByTeam(TEAM_CT) )
return TEAM_UNASSIGNED;
if ( CanBeUsedByTeam(TEAM_TERRORIST) )
return TEAM_TERRORIST;
if ( CanBeUsedByTeam(TEAM_CT) )
return TEAM_CT;
return TEAM_UNASSIGNED;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CCStrike15ItemDefinition::CanBeUsedByAllTeams( void ) const
{
for ( int iTeam = 1; iTeam < (LOADOUT_COUNT-1); iTeam++ )
{
if ( !CanBeUsedByTeam(iTeam) )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CCStrike15ItemDefinition::CanBePlacedInSlot( int nSlot ) const
{
for ( int i = 0; i < LOADOUT_COUNT; i++ )
{
if ( m_iLoadoutSlots[i] == nSlot )
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
// Used to convert strings to ints for class usability
const char *g_ClassUsabilityStrings[] =
{
"noteam",
"undefined",
"terrorists", // TEAM_TERRORIST
"counter-terrorists", // TEAM_CT
};
// Loadout positions
const char *g_szLoadoutStrings[] =
{
// Weapons & Equipment
"melee", // LOADOUT_POSITION_MELEE = 0,
"c4", // LOADOUT_POSITION_C4,
"secondary", // LOADOUT_POSITION_SECONDARY0,
"secondary", // LOADOUT_POSITION_SECONDARY1,
"secondary", // LOADOUT_POSITION_SECONDARY2,
"secondary", // LOADOUT_POSITION_SECONDARY3,
"secondary", // LOADOUT_POSITION_SECONDARY4,
"secondary", // LOADOUT_POSITION_SECONDARY5,
"smg", // LOADOUT_POSITION_SMG0,
"smg", // LOADOUT_POSITION_SMG1,
"smg", // LOADOUT_POSITION_SMG2,
"smg", // LOADOUT_POSITION_SMG3,
"smg", // LOADOUT_POSITION_SMG4,
"smg", // LOADOUT_POSITION_SMG5,
"rifle", // LOADOUT_POSITION_RIFLE0,
"rifle", // LOADOUT_POSITION_RIFLE1,
"rifle", // LOADOUT_POSITION_RIFLE2,
"rifle", // LOADOUT_POSITION_RIFLE3,
"rifle", // LOADOUT_POSITION_RIFLE4,
"rifle", // LOADOUT_POSITION_RIFLE5,
"heavy", // LOADOUT_POSITION_HEAVY0,
"heavy", // LOADOUT_POSITION_HEAVY1,
"heavy", // LOADOUT_POSITION_HEAVY2,
"heavy", // LOADOUT_POSITION_HEAVY3,
"heavy", // LOADOUT_POSITION_HEAVY4,
"heavy", // LOADOUT_POSITION_HEAVY5,
"grenade", // LOADOUT_POSITION_GRENADE0,
"grenade", // LOADOUT_POSITION_GRENADE1,
"grenade", // LOADOUT_POSITION_GRENADE2,
"grenade", // LOADOUT_POSITION_GRENADE3,
"grenade", // LOADOUT_POSITION_GRENADE4,
"grenade", // LOADOUT_POSITION_GRENADE5,
"equipment", // LOADOUT_POSITION_EQUIPMENT0,
"equipment", // LOADOUT_POSITION_EQUIPMENT1,
"equipment", // LOADOUT_POSITION_EQUIPMENT2,
"equipment", // LOADOUT_POSITION_EQUIPMENT3,
"equipment", // LOADOUT_POSITION_EQUIPMENT4,
"equipment", // LOADOUT_POSITION_EQUIPMENT5,
"clothing", // LOADOUT_POSITION_CLOTHING_APPEARANCE,
"clothing", // LOADOUT_POSITION_CLOTHING_TORSO,
"clothing", // LOADOUT_POSITION_CLOTHING_LOWERBODY,
"clothing", // LOADOUT_POSITION_CLOTHING_HANDS,
"clothing", // LOADOUT_POSITION_CLOTHING_HAT,
"clothing", // LOADOUT_POSITION_CLOTHING_FACEMASK,
"clothing", // LOADOUT_POSITION_CLOTHING_EYEWEAR,
"clothing", // LOADOUT_POSITION_CLOTHING_CUSTOMHEAD,
"clothing", // LOADOUT_POSITION_CLOTHING_CUSTOMPLAYER,
"misc", // LOADOUT_POSITION_MISC0,
"misc", // LOADOUT_POSITION_MISC1,
"misc", // LOADOUT_POSITION_MISC2,
"misc", // LOADOUT_POSITION_MISC3,
"misc", // LOADOUT_POSITION_MISC4,
"misc", // LOADOUT_POSITION_MISC5,
"misc", // LOADOUT_POSITION_MISC6,
"musickit", // LOADOUT_POSITION_MUSICKIT,
"flair0", // LOADOUT_POSITION_FLAIR0,
"spray", // LOADOUT_POSITION_SPRAY0,
};
// Loadout positions
const char *g_szLoadoutStringsSubPositions[] =
{
// Weapons & Equipment
"melee", // LOADOUT_POSITION_MELEE = 0,
"c4", // LOADOUT_POSITION_C4,
"secondary0", // LOADOUT_POSITION_SECONDARY0,
"secondary1", // LOADOUT_POSITION_SECONDARY1,
"secondary2", // LOADOUT_POSITION_SECONDARY2,
"secondary3", // LOADOUT_POSITION_SECONDARY3,
"secondary4", // LOADOUT_POSITION_SECONDARY4,
"secondary5", // LOADOUT_POSITION_SECONDARY5,
"smg0", // LOADOUT_POSITION_SMG0,
"smg1", // LOADOUT_POSITION_SMG1,
"smg2", // LOADOUT_POSITION_SMG2,
"smg3", // LOADOUT_POSITION_SMG3,
"smg4", // LOADOUT_POSITION_SMG4,
"smg5", // LOADOUT_POSITION_SMG5,
"rifle0", // LOADOUT_POSITION_RIFLE0,
"rifle1", // LOADOUT_POSITION_RIFLE1,
"rifle2", // LOADOUT_POSITION_RIFLE2,
"rifle3", // LOADOUT_POSITION_RIFLE3,
"rifle4", // LOADOUT_POSITION_RIFLE4,
"rifle5", // LOADOUT_POSITION_RIFLE5,
"heavy0", // LOADOUT_POSITION_HEAVY0,
"heavy1", // LOADOUT_POSITION_HEAVY1,
"heavy2", // LOADOUT_POSITION_HEAVY2,
"heavy3", // LOADOUT_POSITION_HEAVY3,
"heavy4", // LOADOUT_POSITION_HEAVY4,
"heavy5", // LOADOUT_POSITION_HEAVY5,
"grenade0", // LOADOUT_POSITION_GRENADE0,
"grenade1", // LOADOUT_POSITION_GRENADE1,
"grenade2", // LOADOUT_POSITION_GRENADE2,
"grenade3", // LOADOUT_POSITION_GRENADE3,
"grenade4", // LOADOUT_POSITION_GRENADE4,
"grenade5", // LOADOUT_POSITION_GRENADE5,
"equipment0", // LOADOUT_POSITION_EQUIPMENT0,
"equipment1", // LOADOUT_POSITION_EQUIPMENT1,
"equipment2", // LOADOUT_POSITION_EQUIPMENT2,
"equipment3", // LOADOUT_POSITION_EQUIPMENT3,
"equipment4", // LOADOUT_POSITION_EQUIPMENT4,
"equipment5", // LOADOUT_POSITION_EQUIPMENT5,
"clothing0", // LOADOUT_POSITION_CLOTHING_APPEARANCE,
"clothing1", // LOADOUT_POSITION_CLOTHING_TORSO,
"clothing2", // LOADOUT_POSITION_CLOTHING_LOWERBODY,
"clothing_hands", // LOADOUT_POSITION_CLOTHING_HANDS,
"clothing4", // LOADOUT_POSITION_CLOTHING_HAT,
"clothing5", // LOADOUT_POSITION_CLOTHING_FACEMASK,
"clothing6", // LOADOUT_POSITION_CLOTHING_EYEWEAR,
"clothing7", // LOADOUT_POSITION_CLOTHING_CUSTOMHEAD,
"clothing8", // LOADOUT_POSITION_CLOTHING_CUSTOMPLAYER,
"misc0", // LOADOUT_POSITION_MISC0,
"misc1", // LOADOUT_POSITION_MISC1,
"misc2", // LOADOUT_POSITION_MISC2,
"misc3", // LOADOUT_POSITION_MISC3,
"misc4", // LOADOUT_POSITION_MISC4,
"misc5", // LOADOUT_POSITION_MISC5,
"misc6", // LOADOUT_POSITION_MISC6,
"musickit", // LOADOUT_POSITION_MUSICKIT,
"flair0", // LOADOUT_POSITION_FLAIR0,
"spray0", // LOADOUT_POSITION_SPRAY0,
};
// Loadout positions used to display loadout slots to players (localized)
const char *g_szLoadoutStringsForDisplay[] =
{
"#LoadoutSlot_Melee", // LOADOUT_POSITION_MELEE = 0,
"#LoadoutSlot_C4", // LOADOUT_POSITION_C4,
"#LoadoutSlot_Secondary", // LOADOUT_POSITION_SECONDARY0,
"#LoadoutSlot_Secondary", // LOADOUT_POSITION_SECONDARY1,
"#LoadoutSlot_Secondary", // LOADOUT_POSITION_SECONDARY2,
"#LoadoutSlot_Secondary", // LOADOUT_POSITION_SECONDARY3,
"#LoadoutSlot_Secondary", // LOADOUT_POSITION_SECONDARY4,
"#LoadoutSlot_Secondary", // LOADOUT_POSITION_SECONDARY5,
"#LoadoutSlot_SMG", // LOADOUT_POSITION_SMG0,
"#LoadoutSlot_SMG", // LOADOUT_POSITION_SMG1,
"#LoadoutSlot_SMG", // LOADOUT_POSITION_SMG2,
"#LoadoutSlot_SMG", // LOADOUT_POSITION_SMG3,
"#LoadoutSlot_SMG", // LOADOUT_POSITION_SMG4,
"#LoadoutSlot_SMG", // LOADOUT_POSITION_SMG5,
"#LoadoutSlot_Rifle", // LOADOUT_POSITION_RIFLE0,
"#LoadoutSlot_Rifle", // LOADOUT_POSITION_RIFLE1,
"#LoadoutSlot_Rifle", // LOADOUT_POSITION_RIFLE2,
"#LoadoutSlot_Rifle", // LOADOUT_POSITION_RIFLE3,
"#LoadoutSlot_Rifle", // LOADOUT_POSITION_RIFLE4,
"#LoadoutSlot_Rifle", // LOADOUT_POSITION_RIFLE5,
"#LoadoutSlot_Heavy", // LOADOUT_POSITION_HEAVY0,
"#LoadoutSlot_Heavy", // LOADOUT_POSITION_HEAVY1,
"#LoadoutSlot_Heavy", // LOADOUT_POSITION_HEAVY2,
"#LoadoutSlot_Heavy", // LOADOUT_POSITION_HEAVY3,
"#LoadoutSlot_Heavy", // LOADOUT_POSITION_HEAVY4,
"#LoadoutSlot_Heavy", // LOADOUT_POSITION_HEAVY5,
"#LoadoutSlot_Grenade", // LOADOUT_POSITION_GRENADE0,
"#LoadoutSlot_Grenade", // LOADOUT_POSITION_GRENADE1,
"#LoadoutSlot_Grenade", // LOADOUT_POSITION_GRENADE2,
"#LoadoutSlot_Grenade", // LOADOUT_POSITION_GRENADE3,
"#LoadoutSlot_Grenade", // LOADOUT_POSITION_GRENADE4,
"#LoadoutSlot_Grenade", // LOADOUT_POSITION_GRENADE5,
"#LoadoutSlot_Equipment", // LOADOUT_POSITION_EQUIPMENT0,
"#LoadoutSlot_Equipment", // LOADOUT_POSITION_EQUIPMENT1,
"#LoadoutSlot_Equipment", // LOADOUT_POSITION_EQUIPMENT2,
"#LoadoutSlot_Equipment", // LOADOUT_POSITION_EQUIPMENT3,
"#LoadoutSlot_Equipment", // LOADOUT_POSITION_EQUIPMENT4,
"#LoadoutSlot_Equipment", // LOADOUT_POSITION_EQUIPMENT5,
"#LoadoutSlot_Clothing", // LOADOUT_POSITION_CLOTHING_APPEARANCE,
"#LoadoutSlot_Clothing", // LOADOUT_POSITION_CLOTHING_TORSO,
"#LoadoutSlot_Clothing", // LOADOUT_POSITION_CLOTHING_LOWERBODY,
"#LoadoutSlot_Clothing_hands", // LOADOUT_POSITION_CLOTHING_HANDS,
"#LoadoutSlot_Clothing", // LOADOUT_POSITION_CLOTHING_HAT,
"#LoadoutSlot_Clothing", // LOADOUT_POSITION_CLOTHING_FACEMASK,
"#LoadoutSlot_Clothing", // LOADOUT_POSITION_CLOTHING_EYEWEAR,
"#LoadoutSlot_Clothing", // LOADOUT_POSITION_CLOTHING_CUSTOMHEAD,
"#LoadoutSlot_Clothing", // LOADOUT_POSITION_CLOTHING_CUSTOMPLAYER,
"#LoadoutSlot_Misc", // LOADOUT_POSITION_MISC0,
"#LoadoutSlot_Misc", // LOADOUT_POSITION_MISC1,
"#LoadoutSlot_Misc", // LOADOUT_POSITION_MISC2,
"#LoadoutSlot_Misc", // LOADOUT_POSITION_MISC3,
"#LoadoutSlot_Misc", // LOADOUT_POSITION_MISC4,
"#LoadoutSlot_Misc", // LOADOUT_POSITION_MISC5,
"#LoadoutSlot_Misc", // LOADOUT_POSITION_MISC6,
"#LoadoutSlot_MusicKit", // LOADOUT_POSITION_MUSICKIT,
"#LoadoutSlot_Flair", // LOADOUT_POSITION_FLAIR0,
"#LoadoutSlot_Spray", // LOADOUT_POSITION_SPRAY0,
};
/*
// Weapon types
const char *g_szWeaponTypeSubstrings[TF_WPN_TYPE_COUNT] =
{
// Weapons & Equipment
"PRIMARY",
"SECONDARY",
"MELEE",
"GRENADE",
"BUILDING",
"PDA",
"ITEM1",
"ITEM2",
"HEAD",
"MISC",
"MELEE_ALLCLASS",
"SECONDARY2",
"PRIMARY2"
};
*/
CCStrike15ItemSchema::CCStrike15ItemSchema()
{
COMPILE_TIME_ASSERT( ARRAYSIZE( g_szLoadoutStringsForDisplay ) == LOADOUT_POSITION_COUNT );
COMPILE_TIME_ASSERT( ARRAYSIZE( g_szLoadoutStringsSubPositions ) == LOADOUT_POSITION_COUNT );
COMPILE_TIME_ASSERT( ARRAYSIZE( g_szLoadoutStrings ) == LOADOUT_POSITION_COUNT );
InitializeStringTable( &g_ClassUsabilityStrings[0], ARRAYSIZE(g_ClassUsabilityStrings), &m_vecClassUsabilityStrings );
Assert( m_vecClassUsabilityStrings.Count() == LOADOUT_COUNT );
InitializeStringTable( &g_szLoadoutStrings[0], ARRAYSIZE(g_szLoadoutStrings), &m_vecLoadoutStrings );
Assert( m_vecLoadoutStrings.Count() == LOADOUT_POSITION_COUNT );
InitializeStringTable( &g_szLoadoutStringsSubPositions[0], ARRAYSIZE(g_szLoadoutStringsSubPositions), &m_vecLoadoutStringsSubPositions );
Assert( m_vecLoadoutStringsSubPositions.Count() == LOADOUT_POSITION_COUNT );
InitializeStringTable( &g_szLoadoutStringsForDisplay[0], ARRAYSIZE(g_szLoadoutStringsForDisplay), &m_vecLoadoutStringsForDisplay );
Assert( m_vecLoadoutStringsForDisplay.Count() == LOADOUT_POSITION_COUNT );
// InitializeStringTable( &g_szWeaponTypeSubstrings[0], ARRAYSIZE(g_szWeaponTypeSubstrings), &m_vecWeaponTypeSubstrings );
// Assert( m_vecWeaponTypeSubstrings.Count() == TF_WPN_TYPE_COUNT );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCStrike15ItemSchema::InitializeStringTable( const char **ppStringTable, unsigned int unStringCount, CUtlVector<const char *> *out_pvecStringTable )
{
Assert( ppStringTable != NULL );
Assert( out_pvecStringTable != NULL );
Assert( out_pvecStringTable->Count() == 0 );
for ( unsigned int i = 0; i < unStringCount; i++ )
{
Assert( ppStringTable[i] != NULL );
out_pvecStringTable->AddToTail( ppStringTable[i] );
}
}
//-----------------------------------------------------------------------------
// Purpose: Parses game specific items_master data.
//-----------------------------------------------------------------------------
bool CCStrike15ItemSchema::BInitSchema( KeyValues *pKVRawDefinition, CUtlVector<CUtlString> *pVecErrors )
{
return CEconItemSchema::BInitSchema( pKVRawDefinition, pVecErrors );
}
@@ -0,0 +1,118 @@
//========= Copyright (c), Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef CSTRIKE15_ITEM_SCHEMA_H
#define CSTRIKE15_ITEM_SCHEMA_H
#ifdef _WIN32
#pragma once
#endif
#include "econ_item_schema.h"
#include "cstrike15_item_constants.h"
class CCStrike15ItemDefinition : public CEconItemDefinition
{
public:
// Constructor
CCStrike15ItemDefinition();
// CCStrike15ItemDefinition interface.
virtual bool BInitFromKV( KeyValues *pKVItem, CEconItemSchema &schemaa, CUtlVector<CUtlString> *pVecErrors = NULL );
#ifndef GC_DLL
virtual bool BInitFromTestItemKVs( int iNewDefIndex, KeyValues *pKVItem, CEconItemSchema &schemaa );
#endif
virtual void CopyPolymorphic( const CEconItemDefinition *pSourceDef );
#ifndef GC_DLL
virtual void GeneratePrecacheModelStrings( bool bDynamicLoad, CUtlVector<const char *> *out_pVecModelStrings );
#endif // !GC_DLL
int GetAnimSlot( void ) const { return m_iAnimationSlot; }
// Class & Slot handling
int GetDefaultLoadoutSlot( void ) const { return m_iDefaultLoadoutSlot; }
const CBitVec<LOADOUT_COUNT> *GetClassUsability( void ) const { return &m_vbClassUsability; }
void FilloutSlotUsage( CBitVec<LOADOUT_COUNT> *pBV ) const;
bool CanBeUsedByTeam( int iTeam ) const { return m_vbClassUsability.IsBitSet( iTeam ); }
int GetUsedByTeam( void ) const;
bool CanBeUsedByAllTeams( void ) const;
bool IsSupplyCrate( void ) const { return m_bIsSupplyCrate; }
// Items that share a slot (m4, cz/p250) have special rules
bool SharesSlot( void ) const { return m_bItemSharesEquipSlot; }
bool CanBePlacedInSlot( int nSlot ) const;
const char *GetPlayerDisplayModel( int iTeam ) const { Assert( iTeam >= 0 && iTeam < LOADOUT_COUNT ); return m_pszPlayerDisplayModel[iTeam]; }
int GetLoadoutSlot( int iLoadoutClass ) const;
#ifndef GC_DLL
bool IsAWearable( int iSlot ) const;
bool IsContentStreamable() const;
#endif // !GC_DLL
private:
// The load-out slot that this item can be placed into.
int m_iDefaultLoadoutSlot;
int m_iAnimationSlot;
// The .mdl file used for this item when it's being carried by a player.
const char *m_pszPlayerDisplayModel[LOADOUT_COUNT];
// Specifies which class can use this item.
CBitVec<LOADOUT_COUNT> m_vbClassUsability;
int m_iLoadoutSlots[LOADOUT_COUNT]; // Slot that each class places the item into.
bool m_bIsSupplyCrate : 1;
bool m_bItemSharesEquipSlot : 1;
};
class CCStrike15ItemSchema : public CEconItemSchema
{
public:
CCStrike15ItemSchema();
CCStrike15ItemDefinition *GetTFItemDefinition( int iItemIndex )
{
return (CCStrike15ItemDefinition *)GetItemDefinition( iItemIndex );
}
const CUtlVector<const char *>& GetClassUsabilityStrings() const { return m_vecClassUsabilityStrings; }
const CUtlVector<const char *>& GetLoadoutStrings() const { return m_vecLoadoutStrings; }
const CUtlVector<const char *>& GetLoadoutStringsSubPositions() const { return m_vecLoadoutStringsSubPositions; }
const CUtlVector<const char *>& GetLoadoutStringsForDisplay() const { return m_vecLoadoutStringsForDisplay; }
const CUtlVector<const char *>& GetWeaponTypeSubstrings() const { return m_vecWeaponTypeSubstrings; }
static const char k_rchCommunitySupportPassItemDefName[];
public:
// CEconItemSchema interface.
virtual CEconItemDefinition *CreateEconItemDefinition() { return new CCStrike15ItemDefinition; }
virtual bool BInitSchema( KeyValues *pKVRawDefinition, CUtlVector<CUtlString> *pVecErrors = NULL );
private:
void InitializeStringTable( const char **ppStringTable, unsigned int unStringCount, CUtlVector<const char *> *out_pvecStringTable );
CUtlVector<const char *> m_vecClassUsabilityStrings;
CUtlVector<const char *> m_vecLoadoutStrings;
CUtlVector<const char *> m_vecLoadoutStringsSubPositions;
CUtlVector<const char *> m_vecLoadoutStringsForDisplay;
CUtlVector<const char *> m_vecWeaponTypeSubstrings;
};
extern const char *g_szLoadoutStrings[ LOADOUT_POSITION_COUNT ];
extern const char *g_szLoadoutStringsForDisplay[ LOADOUT_POSITION_COUNT ];
#endif // CSTRIKE15_ITEM_SCHEMA_H
@@ -0,0 +1,44 @@
//========= Copyright © 1996-2003, Valve LLC, All rights reserved. ============
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "cstrike15_item_system.h"
#include "cstrike15_item_inventory.h"
#include "econ_item_inventory.h"
//-----------------------------------------------------------------------------
// Purpose: Generate the base item for a class's loadout slot
//-----------------------------------------------------------------------------
int CCStrike15ItemSystem::GenerateBaseItem( baseitemcriteria_t *pCriteria )
{
Assert( ( pCriteria->iClass != 0 ) || ( pCriteria->iSlot == LOADOUT_POSITION_MUSICKIT ) );
Assert( pCriteria->iSlot != LOADOUT_POSITION_INVALID );
// Some slots don't have base items (i.e. were added after launch)
if ( !SlotContainsBaseItems( pCriteria->iSlot ) )
return INVALID_ITEM_INDEX;
CItemSelectionCriteria criteria;
criteria.SetQuality( AE_NORMAL );
criteria.SetRarity( 1 );
criteria.SetItemLevel( 1 );
criteria.BAddCondition( "baseitem", k_EOperator_String_EQ, "1", true );
criteria.BAddCondition( "default_slot_item", k_EOperator_String_EQ, "1", true );
criteria.SetExplicitQualityMatch( true );
CSInventoryManager()->AddBaseItemCriteria( pCriteria, &criteria );
int iChosenItem = GenerateRandomItem( &criteria, NULL );
return iChosenItem;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CCStrike15ItemSystem *CStrike15ItemSystem( void )
{
CEconItemSystem *pItemSystem = ItemSystem();
Assert( dynamic_cast<CCStrike15ItemSystem *>( pItemSystem ) != NULL );
return (CCStrike15ItemSystem *)pItemSystem;
}
@@ -0,0 +1,41 @@
//========= Copyright © 1996-2003, Valve LLC, All rights reserved. ============
//
// Purpose:
//
//=============================================================================
#ifndef CSTRIKE15_ITEM_SYSTEM_H
#define CSTRIKE15_ITEM_SYSTEM_H
#ifdef _WIN32
#pragma once
#endif
#include "econ_item_system.h"
//#include "cstrike15_item_constants.h"
//-----------------------------------------------------------------------------
// Criteria used by the system to generate a base item for a slot in a class's loadout
//-----------------------------------------------------------------------------
struct baseitemcriteria_t
{
baseitemcriteria_t()
{
iClass = 0;
iSlot = LOADOUT_POSITION_INVALID;
}
int iClass;
int iSlot;
};
class CCStrike15ItemSystem : public CEconItemSystem
{
public:
// Select and return the base item definition index for a class's load-out slot
virtual int GenerateBaseItem( baseitemcriteria_t *pCriteria );
};
CCStrike15ItemSystem *CStrike15ItemSystem( void );
#endif // CSTRIKE15_ITEM_SYSTEM_H
@@ -0,0 +1,601 @@
//====== Copyright (c) 2013, Valve Corporation, All rights reserved. ========//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//===========================================================================//
//
// Purpose: The file defines our Google Protocol Buffers which are used in over
// the wire messages for the Source engine.
//
//=============================================================================
// We care more about speed than code size
option optimize_for = SPEED;
// We don't use the service generation functionality
option cc_generic_services = false;
//
// STYLE NOTES:
//
// Use CamelCase CMsgMyMessageName style names for messages.
//
// Use lowercase _ delimited names like my_steam_id for field names, this is non-standard for Steam,
// but plays nice with the Google formatted code generation.
//
// Try not to use required fields ever. Only do so if you are really really sure you'll never want them removed.
// Optional should be preffered as it will make versioning easier and cleaner in the future if someone refactors
// your message and wants to remove or rename fields.
//
// Use fixed64 for JobId_t, GID_t, or SteamID. This is appropriate for any field that is normally
// going to be larger than 2^56. Otherwise use int64 for 64 bit values that are frequently smaller
// than 2^56 as it will safe space on the wire in those cases.
//
// Similar to fixed64, use fixed32 for RTime32 or other 32 bit values that are frequently larger than
// 2^28. It will safe space in those cases, otherwise use int32 which will safe space for smaller values.
// An exception to this rule for RTime32 is if the value will frequently be zero rather than set to an actual
// time.
//
import "google/protobuf/descriptor.proto";
// for CMsgVector, etc.
import "netmessages.proto";
import "cstrike15_gcmessages.proto";
//=============================================================================
// CStrike15 User Messages
//=============================================================================
enum ECstrike15UserMessages
{
CS_UM_VGUIMenu = 1;
CS_UM_Geiger = 2;
CS_UM_Train = 3;
CS_UM_HudText = 4;
CS_UM_SayText = 5;
CS_UM_SayText2 = 6;
CS_UM_TextMsg = 7;
CS_UM_HudMsg = 8;
CS_UM_ResetHud = 9;
CS_UM_GameTitle = 10;
CS_UM_Shake = 12;
CS_UM_Fade = 13; // fade HUD in/out
CS_UM_Rumble = 14;
CS_UM_CloseCaption = 15;
CS_UM_CloseCaptionDirect = 16;
CS_UM_SendAudio = 17;
CS_UM_RawAudio = 18;
CS_UM_VoiceMask = 19;
CS_UM_RequestState = 20;
CS_UM_Damage = 21;
CS_UM_RadioText = 22;
CS_UM_HintText = 23;
CS_UM_KeyHintText = 24;
CS_UM_ProcessSpottedEntityUpdate = 25;
CS_UM_ReloadEffect = 26;
CS_UM_AdjustMoney = 27;
CS_UM_UpdateTeamMoney = 28;
CS_UM_StopSpectatorMode = 29;
CS_UM_KillCam = 30;
CS_UM_DesiredTimescale = 31;
CS_UM_CurrentTimescale = 32;
CS_UM_AchievementEvent = 33;
CS_UM_MatchEndConditions = 34;
CS_UM_DisconnectToLobby = 35;
CS_UM_PlayerStatsUpdate = 36;
CS_UM_DisplayInventory = 37;
CS_UM_WarmupHasEnded = 38;
CS_UM_ClientInfo = 39;
CS_UM_XRankGet = 40; // Get ELO Rank Value from Client
CS_UM_XRankUpd = 41; // Update ELO Rank Value on Client
CS_UM_CallVoteFailed = 45;
CS_UM_VoteStart = 46;
CS_UM_VotePass = 47;
CS_UM_VoteFailed = 48;
CS_UM_VoteSetup = 49;
CS_UM_ServerRankRevealAll = 50;
CS_UM_SendLastKillerDamageToClient = 51;
CS_UM_ServerRankUpdate = 52;
CS_UM_ItemPickup = 53;
CS_UM_ShowMenu = 54; // show hud menu
CS_UM_BarTime = 55; // For the C4 progress bar.
CS_UM_AmmoDenied = 56;
CS_UM_MarkAchievement = 57;
CS_UM_MatchStatsUpdate = 58;
CS_UM_ItemDrop = 59;
CS_UM_GlowPropTurnOff = 60;
CS_UM_SendPlayerItemDrops = 61;
CS_UM_RoundBackupFilenames = 62;
CS_UM_SendPlayerItemFound = 63;
CS_UM_ReportHit = 64;
CS_UM_XpUpdate = 65;
CS_UM_QuestProgress = 66; // Send notification to user when quest progress was made.
CS_UM_ScoreLeaderboardData = 67; // Game server broadcasting match end scoreboard and leaderboard data
CS_UM_PlayerDecalDigitalSignature = 68; // Game server can ask client to provide a digital signature for decal data
}
//=============================================================================
message CCSUsrMsg_VGUIMenu
{
optional string name = 1;
optional bool show = 2;
message Subkey
{
optional string name = 1;
optional string str = 2;
}
repeated Subkey subkeys = 3;
}
message CCSUsrMsg_Geiger
{
optional int32 range = 1;
}
message CCSUsrMsg_Train
{
optional int32 train = 1;
}
message CCSUsrMsg_HudText
{
optional string text = 1;
}
message CCSUsrMsg_SayText
{
optional int32 ent_idx = 1;
optional string text = 2;
optional bool chat = 3;
optional bool textallchat = 4;
}
message CCSUsrMsg_SayText2
{
optional int32 ent_idx = 1;
optional bool chat = 2;
optional string msg_name = 3;
repeated string params = 4;
optional bool textallchat = 5;
}
message CCSUsrMsg_TextMsg
{
optional int32 msg_dst = 1;
repeated string params = 3;
}
message CCSUsrMsg_HudMsg
{
optional int32 channel = 1;
optional CMsgVector2D pos = 2;
optional CMsgRGBA clr1 = 3;
optional CMsgRGBA clr2 = 4;
optional int32 effect = 5;
optional float fade_in_time = 6;
optional float fade_out_time = 7;
optional float hold_time = 9;
optional float fx_time = 10;
optional string text = 11;
}
message CCSUsrMsg_Shake
{
optional int32 command = 1;
optional float local_amplitude = 2;
optional float frequency = 3;
optional float duration = 4;
}
message CCSUsrMsg_Fade
{
optional int32 duration = 1;
optional int32 hold_time = 2;
optional int32 flags = 3; // fade type (in / out)
optional CMsgRGBA clr = 4;
}
message CCSUsrMsg_Rumble
{
optional int32 index = 1;
optional int32 data = 2;
optional int32 flags = 3;
}
message CCSUsrMsg_CloseCaption
{
optional uint32 hash = 1;
optional int32 duration = 2;
optional bool from_player = 3;
}
message CCSUsrMsg_CloseCaptionDirect
{
optional uint32 hash = 1;
optional int32 duration = 2;
optional bool from_player = 3;
}
message CCSUsrMsg_SendAudio
{
optional string radio_sound = 1;
}
message CCSUsrMsg_RawAudio
{
optional int32 pitch = 1;
optional int32 entidx = 2;
optional float duration = 3;
optional string voice_filename = 4;
}
message CCSUsrMsg_VoiceMask
{
message PlayerMask
{
optional int32 game_rules_mask = 1;
optional int32 ban_masks = 2;
}
repeated PlayerMask player_masks = 1;
optional bool player_mod_enable = 2;
}
message CCSUsrMsg_Damage
{
optional int32 amount = 1;
optional CMsgVector inflictor_world_pos = 2;
optional int32 victim_entindex = 3;
}
message CCSUsrMsg_RadioText
{
optional int32 msg_dst = 1;
optional int32 client = 2;
optional string msg_name = 3;
repeated string params = 4;
}
message CCSUsrMsg_HintText
{
optional string text = 1;
}
message CCSUsrMsg_KeyHintText
{
repeated string hints = 1;
}
// gurjeets - Message below is slightly bigger in size than the non-protobuf version,
// by around 8 bits.
message CCSUsrMsg_ProcessSpottedEntityUpdate
{
optional bool new_update = 1;
message SpottedEntityUpdate
{
optional int32 entity_idx = 1;
optional int32 class_id = 2;
optional int32 origin_x = 3;
optional int32 origin_y = 4;
optional int32 origin_z = 5;
optional int32 angle_y = 6;
optional bool defuser = 7;
optional bool player_has_defuser = 8;
optional bool player_has_c4 = 9;
}
repeated SpottedEntityUpdate entity_updates = 2;
}
message CCSUsrMsg_SendPlayerItemDrops
{
repeated CEconItemPreviewDataBlock entity_updates = 1;
}
message CCSUsrMsg_SendPlayerItemFound
{
optional CEconItemPreviewDataBlock iteminfo = 1;
optional int32 entindex = 2;
}
message CCSUsrMsg_ReloadEffect
{
optional int32 entidx = 1;
optional int32 actanim = 2;
optional float origin_x = 3;
optional float origin_y = 4;
optional float origin_z = 5;
}
message CCSUsrMsg_AdjustMoney
{
optional int32 amount = 1;
}
// This code allowed us to measure discrepency between client and server bullet hits.
// It became obsolete when we started using a separate seed for client and server
// to eliminate 'rage' hacks.
//
message CCSUsrMsg_ReportHit
{
optional float pos_x = 1;
optional float pos_y = 2;
optional float timestamp = 4;
optional float pos_z = 3;
}
message CCSUsrMsg_KillCam
{
optional int32 obs_mode = 1;
optional int32 first_target = 2;
optional int32 second_target = 3;
}
message CCSUsrMsg_DesiredTimescale
{
optional float desired_timescale = 1;
optional float duration_realtime_sec = 2;
optional int32 interpolator_type = 3;
optional float start_blend_time = 4;
}
message CCSUsrMsg_CurrentTimescale
{
optional float cur_timescale = 1;
}
message CCSUsrMsg_AchievementEvent
{
optional int32 achievement = 1;
optional int32 count = 2;
optional int32 user_id = 3;
}
message CCSUsrMsg_MatchEndConditions
{
optional int32 fraglimit = 1;
optional int32 mp_maxrounds = 2;
optional int32 mp_winlimit = 3;
optional int32 mp_timelimit = 4;
}
message CCSUsrMsg_PlayerStatsUpdate
{
optional int32 version = 1;
message Stat
{
optional int32 idx = 1;
optional int32 delta = 2;
}
repeated Stat stats = 4;
optional int32 user_id = 5;
optional int32 crc = 6;
}
message CCSUsrMsg_DisplayInventory
{
optional bool display = 1;
optional int32 user_id = 2;
}
message CCSUsrMsg_QuestProgress
{
optional uint32 quest_id = 1;
optional uint32 normal_points = 2;
optional uint32 bonus_points = 3;
optional bool is_event_quest = 4;
}
message CCSUsrMsg_ScoreLeaderboardData
{
optional ScoreLeaderboardData data = 1;
}
message CCSUsrMsg_PlayerDecalDigitalSignature
{
optional PlayerDecalDigitalSignature data = 1;
}
message CCSUsrMsg_XRankGet
{
optional int32 mode_idx = 1;
optional int32 controller = 2;
}
message CCSUsrMsg_XRankUpd
{
optional int32 mode_idx = 1;
optional int32 controller = 2;
optional int32 ranking = 3;
}
message CCSUsrMsg_CallVoteFailed
{
optional int32 reason = 1;
optional int32 time = 2;
}
message CCSUsrMsg_VoteStart
{
optional int32 team = 1;
optional int32 ent_idx = 2;
optional int32 vote_type = 3;
optional string disp_str = 4;
optional string details_str = 5;
optional string other_team_str = 6;
optional bool is_yes_no_vote = 7;
}
message CCSUsrMsg_VotePass
{
optional int32 team = 1;
optional int32 vote_type = 2;
optional string disp_str= 3;
optional string details_str = 4;
}
message CCSUsrMsg_VoteFailed
{
optional int32 team = 1;
optional int32 reason = 2;
}
message CCSUsrMsg_VoteSetup
{
repeated string potential_issues = 1;
}
message CCSUsrMsg_SendLastKillerDamageToClient
{
optional int32 num_hits_given = 1;
optional int32 damage_given = 2;
optional int32 num_hits_taken = 3;
optional int32 damage_taken = 4;
}
message CCSUsrMsg_ServerRankUpdate
{
message RankUpdate
{
optional int32 account_id = 1;
optional int32 rank_old = 2;
optional int32 rank_new = 3;
optional int32 num_wins = 4;
optional float rank_change = 5;
}
repeated RankUpdate rank_update = 1;
}
message CCSUsrMsg_XpUpdate
{
optional CMsgGCCstrike15_v2_GC2ServerNotifyXPRewarded data = 1;
}
message CCSUsrMsg_ItemPickup
{
optional string item = 1;
}
message CCSUsrMsg_ShowMenu
{
optional int32 bits_valid_slots = 1;
optional int32 display_time = 2;
optional string menu_string = 3;
}
message CCSUsrMsg_BarTime
{
optional string time = 1;
}
message CCSUsrMsg_AmmoDenied
{
optional int32 ammoIdx = 1;
}
message CCSUsrMsg_MarkAchievement
{
optional string achievement = 1;
}
message CCSUsrMsg_MatchStatsUpdate
{
optional string update = 1;
}
message CCSUsrMsg_ItemDrop
{
optional int64 itemid = 1;
optional bool death = 2;
}
message CCSUsrMsg_GlowPropTurnOff
{
optional int32 entidx = 1;
}
message CCSUsrMsg_RoundBackupFilenames
{
optional int32 count = 1;
optional int32 index = 2;
optional string filename = 3;
optional string nicename = 4;
}
//=============================================================================
// Messages where the data seems to be irrelevant
//=============================================================================
message CCSUsrMsg_ResetHud
{
optional bool reset = 1;
}
message CCSUsrMsg_GameTitle
{
optional int32 dummy = 1;
}
message CCSUsrMsg_RequestState
{
optional int32 dummy = 1;
}
message CCSUsrMsg_StopSpectatorMode
{
optional int32 dummy = 1;
}
message CCSUsrMsg_DisconnectToLobby
{
optional int32 dummy = 1;
}
message CCSUsrMsg_WarmupHasEnded
{
optional int32 dummy = 1;
}
message CCSUsrMsg_ClientInfo
{
optional int32 dummy = 1;
}
message CCSUsrMsg_ServerRankRevealAll
{
optional int32 seconds_till_shutdown = 1;
}
@@ -0,0 +1,24 @@
$MacroRequired PROTOBUF_BUILDER_INCLUDED
$Project
{
$Folder "Protobuf Files"
{
$File "$SRCDIR\game\shared\cstrike15\cstrike15_usermessages.proto"
$Folder "Generated Files"
{
$DynamicFile "$GENERATED_PROTO_DIR\cstrike15_usermessages.pb.h"
$DynamicFile "$GENERATED_PROTO_DIR\cstrike15_usermessages.pb.cc"
{
$Configuration
{
$Compiler [$WINDOWS]
{
$Create/UsePrecompiledHeader "Not Using Precompiled Headers"
}
}
}
}
}
}
+384
View File
@@ -0,0 +1,384 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "decoy_projectile.h"
#include "engine/IEngineSound.h"
#include "keyvalues.h"
#include "weapon_csbase.h"
#include "particle_parse.h"
#if defined( CLIENT_DLL )
#include "c_cs_player.h"
#else
#include "sendproxy.h"
#include "cs_player.h"
#include "bot_manager.h"
#endif
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
#if defined( CLIENT_DLL )
IMPLEMENT_CLIENTCLASS_DT( C_DecoyProjectile, DT_DecoyProjectile, CDecoyProjectile )
END_RECV_TABLE()
//--------------------------------------------------------------------------------------------------------
void C_DecoyProjectile::OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect )
{
if ( FStrEq( pszParticleName, "weapon_decoy_ground_effect" ) )
{
m_decoyParticleEffect = pNewParticleEffect;
}
}
//--------------------------------------------------------------------------------------------------------
void C_DecoyProjectile::OnParticleEffectDeleted( CNewParticleEffect *pParticleEffect )
{
if ( m_decoyParticleEffect == pParticleEffect )
{
m_decoyParticleEffect = NULL;
}
}
//--------------------------------------------------------------------------------------------------------
bool C_DecoyProjectile::Simulate( void )
{
// we are still moving
if ( GetAbsVelocity().Length() > 0.1f )
{
return true;
}
if ( !m_decoyParticleEffect.IsValid() )
{
DispatchParticleEffect( "weapon_decoy_ground_effect", PATTACH_POINT_FOLLOW, this, "Wick" );
}
else
{
m_decoyParticleEffect->SetSortOrigin( GetAbsOrigin() );
m_decoyParticleEffect->SetNeedsBBoxUpdate( true );
}
BaseClass::Simulate();
return true;
}
#else // GAME_DLL
#define GRENADE_MODEL "models/Weapons/w_eq_decoy_dropped.mdl"
LINK_ENTITY_TO_CLASS( decoy_projectile, CDecoyProjectile );
PRECACHE_REGISTER( decoy_projectile );
IMPLEMENT_SERVERCLASS_ST( CDecoyProjectile, DT_DecoyProjectile )
END_SEND_TABLE()
BEGIN_DATADESC( CDecoyProjectile )
DEFINE_THINKFUNC( Think_Detonate ),
DEFINE_THINKFUNC( GunfireThink )
END_DATADESC()
struct DecoyWeaponProfile
{
CSWeaponType weaponType;
int minShots;
int maxShots;
float extraDelay;
float pauseMin;
float pauseMax;
};
DecoyWeaponProfile gDecoyWeaponProfiles[] =
{
// CSWeaponType minShots, maxShots, extraDelay, pauseMin, pauseMax
{ WEAPONTYPE_PISTOL, 1, 3, 0.3f, 0.5f, 4.0f },
{ WEAPONTYPE_SUBMACHINEGUN, 1, 5, 0.0f, 0.5f, 4.0f },
{ WEAPONTYPE_RIFLE, 1, 3, 0.5f, 0.5f, 4.0f },
{ WEAPONTYPE_SHOTGUN, 1, 3, 0.0f, 0.5f, 4.0f },
{ WEAPONTYPE_SNIPER_RIFLE, 1, 3, 0.5f, 0.5f, 4.0f },
{ WEAPONTYPE_MACHINEGUN, 6, 20, 0.0f, 0.5f, 4.0f },
};
// --------------------------------------------------------------------------------------------------- //
// CFlashbangProjectile implementation.
// --------------------------------------------------------------------------------------------------- //
CDecoyProjectile* CDecoyProjectile::Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
const CCSWeaponInfo& weaponInfo )
{
CDecoyProjectile *pGrenade = ( CDecoyProjectile* )CBaseEntity::Create( "decoy_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->SetTimer( 2.0f );
pGrenade->SetAbsVelocity( velocity );
pGrenade->SetupInitialTransmittedGrenadeVelocity( velocity );
pGrenade->SetThrower( pOwner );
pGrenade->m_flDamage = 25.0f; // 25 = 1/4 of HEGrenade Damage
pGrenade->m_DmgRadius = pGrenade->m_flDamage * 3.5f; // Changing damage will change the radius
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
pGrenade->ApplyLocalAngularVelocityImpulse( angVelocity );
pGrenade->SetTouch( &CBaseGrenade::BounceTouch );
pGrenade->SetGravity( BaseClass::GetGrenadeGravity() );
pGrenade->SetFriction( BaseClass::GetGrenadeFriction() );
pGrenade->SetElasticity( BaseClass::GetGrenadeElasticity() );
pGrenade->m_pWeaponInfo = &weaponInfo;
ASSERT(pOwner != NULL);
// pick a weapon based on what the player is carrying, falling back to default starting pistols
CBaseCombatWeapon* pPrimaryWeapon = pOwner->Weapon_GetSlot(WEAPON_SLOT_RIFLE);
CBaseCombatWeapon* pSecondaryWeapon = pOwner->Weapon_GetSlot(WEAPON_SLOT_PISTOL);
pGrenade->m_decoyWeaponDefIndex = INVALID_ITEM_DEF_INDEX;
pGrenade->m_decoyWeaponSoundType = SINGLE;
if ( pPrimaryWeapon != NULL )
{
CEconItemView* pItem = pPrimaryWeapon->GetEconItemView();
if ( pItem && pItem->IsValid() )
{
pGrenade->m_decoyWeaponDefIndex = pItem->GetItemDefinition()->GetDefinitionIndex();
pGrenade->m_decoyWeaponId = WeaponIdFromString( pItem->GetItemDefinition()->GetItemClass() );
CWeaponCSBase *pWeapon = static_cast<CWeaponCSBase *>( pPrimaryWeapon );
if ( pWeapon )
{
pGrenade->m_decoyWeaponSoundType = ( pWeapon->HasSilencer() && pWeapon->IsSilenced() ) ? SPECIAL1 : SINGLE;
}
}
else
{
pGrenade->m_decoyWeaponId = (CSWeaponID)pPrimaryWeapon->GetWeaponID();
}
}
else if ( pSecondaryWeapon != NULL )
{
CEconItemView* pItem = pSecondaryWeapon->GetEconItemView();
if ( pItem && pItem->IsValid() )
{
pGrenade->m_decoyWeaponDefIndex = pItem->GetItemDefinition()->GetDefinitionIndex();
pGrenade->m_decoyWeaponId = WeaponIdFromString( pItem->GetItemDefinition()->GetItemClass() );
CWeaponCSBase *pWeapon = static_cast<CWeaponCSBase *>( pSecondaryWeapon );
if ( pWeapon )
{
pGrenade->m_decoyWeaponSoundType = ( pWeapon->HasSilencer() && pWeapon->IsSilenced() ) ? SPECIAL1 : SINGLE;
}
}
else
{
pGrenade->m_decoyWeaponId = (CSWeaponID)pSecondaryWeapon->GetWeaponID();
}
}
else
{
if ( pOwner->GetTeamNumber() == TEAM_CT )
{
pGrenade->m_decoyWeaponId = WEAPON_HKP2000;
}
else
{
pGrenade->m_decoyWeaponId = WEAPON_GLOCK;
}
}
const CCSWeaponInfo* pDecoyWeaponInfo = GetWeaponInfo(pGrenade->m_decoyWeaponId);
// find the corresponding decoy firing profile
pGrenade->m_pProfile = &gDecoyWeaponProfiles[0];
for ( int i = 0; i < ARRAYSIZE( gDecoyWeaponProfiles ); ++i )
{
if ( gDecoyWeaponProfiles[i].weaponType == pDecoyWeaponInfo->GetWeaponType() )
{
pGrenade->m_pProfile = &gDecoyWeaponProfiles[i];
break;
}
}
pGrenade->SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
return pGrenade;
}
void CDecoyProjectile::SetTimer( float timer )
{
SetThink( &CDecoyProjectile::Think_Detonate );
SetNextThink( gpGlobals->curtime + timer );
TheBots->SetGrenadeRadius( this, 0.0f );
}
void CDecoyProjectile::Think_Detonate( void )
{
#if 1
if ( GetAbsVelocity().Length() > 0.2f )
{
// Still moving. Don't detonate yet.
SetNextThink( gpGlobals->curtime + 0.2f );
return;
}
#endif // 0
CCSPlayer *player = ToCSPlayer( GetThrower() );
if ( player )
{
IGameEvent * event = gameeventmanager->CreateEvent( "decoy_started" );
if ( event )
{
event->SetInt( "userid", player->GetUserID() );
event->SetInt( "entityid", this->entindex() );
event->SetFloat( "x", GetAbsOrigin().x );
event->SetFloat( "y", GetAbsOrigin().y );
event->SetFloat( "z", GetAbsOrigin().z );
gameeventmanager->FireEvent( event );
}
}
m_shotsRemaining = 0;
m_fExpireTime = gpGlobals->curtime + 14.0f; // TODO: Make this Data Driven
SetThink( &CDecoyProjectile::GunfireThink );
TheBots->SetGrenadeRadius( this, DecoyGrenadeRadius );
GunfireThink(); // This will handling the 'Detonate'
}
void CDecoyProjectile::Detonate( void )
{
// [mlowrance] The Decoy is handling it's own detonate.
Assert(!"Decoy grenade handles its own detonation");
}
void CDecoyProjectile::GunfireThink( void )
{
ASSERT(m_pProfile != NULL);
if ( !m_pProfile )
return;
if ( m_shotsRemaining <= 0 )
{
// pick a new burst activity
m_shotsRemaining = RandomInt( m_pProfile->minShots, m_pProfile->maxShots );
}
const CCSWeaponInfo* pWeaponInfo = GetWeaponInfo(m_decoyWeaponId);
CBroadcastRecipientFilter filter;
const char *shootsound = pWeaponInfo->aShootSounds[ m_decoyWeaponSoundType ];
if ( m_decoyWeaponDefIndex != INVALID_ITEM_DEF_INDEX )
{
// Get the item definition
const CEconItemDefinition *pDef = ( m_decoyWeaponDefIndex > 0 ) ? GetItemSchema()->GetItemDefinition( m_decoyWeaponDefIndex ) : NULL;
if ( pDef )
{
const char *pszTempSound = pDef->GetWeaponReplacementSound( m_decoyWeaponSoundType );
if ( pszTempSound )
{
shootsound = pszTempSound;
}
}
}
CSoundParameters params;
if ( GetParametersForSound( shootsound, params, NULL ) )
{
CPASAttenuationFilter filter( this, params.soundlevel );
EmitSound( filter, entindex(), shootsound, &GetLocalOrigin(), 0.0f );
DispatchParticleEffect( "weapon_decoy_ground_effect_shot", GetAbsOrigin(), GetAbsAngles() );
}
// tell the bots about the gunfire
CCSPlayer *pPlayer = ToCSPlayer( GetThrower() );
if ( pPlayer )
{
// allow the bots to react to the "gunfire"
// we need a custom event here, because the "weapon_fire" event assumes
// the gunfire is coming from the player!
IGameEvent * event = gameeventmanager->CreateEvent( "decoy_firing" );
if ( event )
{
event->SetInt( "userid", pPlayer->GetUserID() );
event->SetInt( "entityid", this->entindex() );
event->SetFloat( "x", GetAbsOrigin().x );
event->SetFloat( "y", GetAbsOrigin().y );
event->SetFloat( "z", GetAbsOrigin().z );
gameeventmanager->FireEvent( event );
}
}
if ( --m_shotsRemaining > 0 )
{
SetNextThink( gpGlobals->curtime + pWeaponInfo->GetCycleTime() + RandomFloat( 0.0f, m_pProfile->extraDelay) );
return;
}
if ( gpGlobals->curtime < m_fExpireTime )
{
SetNextThink( gpGlobals->curtime + pWeaponInfo->GetCycleTime() + RandomFloat( m_pProfile->pauseMin, m_pProfile->pauseMax ) );
}
else
{
// [mlowrance] Do the damage on Despawn and post event
CCSPlayer *player = ToCSPlayer( GetThrower() );
if ( player )
{
IGameEvent * event = gameeventmanager->CreateEvent( "decoy_detonate" );
if ( event )
{
event->SetInt( "userid", player->GetUserID() );
event->SetInt( "entityid", this->entindex() );
event->SetFloat( "x", GetAbsOrigin().x );
event->SetFloat( "y", GetAbsOrigin().y );
event->SetFloat( "z", GetAbsOrigin().z );
gameeventmanager->FireEvent( event );
}
}
BaseClass::Detonate();
UTIL_Remove( this );
}
}
void CDecoyProjectile::Spawn( void )
{
SetModel( GRENADE_MODEL );
BaseClass::Spawn();
SetBodygroupPreset( "thrown" );
}
void CDecoyProjectile::Precache( void )
{
PrecacheModel( GRENADE_MODEL );
PrecacheScriptSound( "Flashbang.Explode" );
PrecacheScriptSound( "Flashbang.Bounce" );
PrecacheParticleSystem( "weapon_decoy_ground_effect_shot" );
BaseClass::Precache();
}
//TODO: Let physics handle the sound!
void CDecoyProjectile::BounceSound( void )
{
EmitSound( "Flashbang.Bounce" );
}
#endif // GAME_DLL
+79
View File
@@ -0,0 +1,79 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DECOY_PROJECTILE_H
#define DECOY_PROJECTILE_H
#ifdef _WIN32
#pragma once
#endif
#include "basecsgrenade_projectile.h"
#if defined( CLIENT_DLL )
class C_DecoyProjectile : public C_BaseCSGrenadeProjectile
{
public:
DECLARE_CLASS( C_DecoyProjectile, C_BaseCSGrenadeProjectile );
DECLARE_NETWORKCLASS();
virtual bool Simulate( void );
virtual void OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect );
virtual void OnParticleEffectDeleted( CNewParticleEffect *pParticleEffect );
private:
CUtlReference<CNewParticleEffect> m_decoyParticleEffect;
};
#else // GAME_DLL
struct DecoyWeaponProfile;
class CDecoyProjectile : public CBaseCSGrenadeProjectile
{
public:
DECLARE_CLASS( CDecoyProjectile, CBaseCSGrenadeProjectile );
DECLARE_NETWORKCLASS();
DECLARE_DATADESC();
// Overrides.
public:
virtual void Spawn( void );
virtual void Precache( void );
virtual void Detonate( void );
virtual void BounceSound( void );
virtual GrenadeType_t GetGrenadeType( void ) { return GRENADE_TYPE_DECOY; }
// Grenade stuff.
static CDecoyProjectile* Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
const CCSWeaponInfo& weaponInfo );
private:
void Think_Detonate( void );
void GunfireThink( void );
void SetTimer( float timer );
int m_shotsRemaining;
float m_fExpireTime;
DecoyWeaponProfile* m_pProfile;
CSWeaponID m_decoyWeaponId;
item_definition_index_t m_decoyWeaponDefIndex;
WeaponSound_t m_decoyWeaponSoundType;
};
#endif // GAME_DLL
#endif // DECOY_PROJECTILE_H
+129
View File
@@ -0,0 +1,129 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef _DLC_HELPER_H
#define _DLC_HELPER_H
#pragma once
#include "platform.h"
#include "keyvalues.h"
#include "filesystem.h"
class KeyValues;
// Helper methods for DLC
class DLCHelper
{
public:
static inline uint64 GetInstalledDLCMask( void );
// Loads the key values from all installed DLC files matching the file name plus _dlc[id].
// For example, if fileName is "gamemodes.txt" we will look for "gamemodes_dlc1.txt", "gamemodes_dlc2.txt", etc...
// The key values from the dlc files will then be merged in (with update) to the passed
// in key values.
static inline void AppendDLCKeyValues( KeyValues* pKeyValues, const char* fileName, const char* startDir = NULL );
};
uint64 DLCHelper::GetInstalledDLCMask( void )
{
// Assert( g_pMatchFramework );
// return g_pMatchFramework->GetMatchSystem()->GetDlcManager()->GetDataInfo()->GetUint64( "@info/installed" );
//static ConVarRef mm_dlcs_mask_fake( "mm_dlcs_mask_fake" );
//char const *szFakeDlcsString = mm_dlcs_mask_fake.GetString();
//if ( *szFakeDlcsString )
// return atoi( szFakeDlcsString );
//static ConVarRef mm_dlcs_mask_extras( "mm_dlcs_mask_extras" );
//uint64 uiDLCmask = ( unsigned ) mm_dlcs_mask_extras.GetInt();
uint64 uiDLCmask = 0;
bool bSearchPath = false;
int numDLCs = g_pFullFileSystem->IsAnyDLCPresent( &bSearchPath );
// If we need to, trigger the mounting of DLC
if ( !bSearchPath )
{
g_pFullFileSystem->AddDLCSearchPaths();
}
for ( int j = 0; j < numDLCs; ++ j )
{
unsigned int uiDlcHeader = 0;
if ( !g_pFullFileSystem->GetAnyDLCInfo( j, &uiDlcHeader, NULL, 0 ) )
continue;
int idDLC = DLC_LICENSE_ID( uiDlcHeader );
if ( idDLC < 1 || idDLC >= 31 )
continue; // unsupported DLC id
uiDLCmask |= ( 1ull << idDLC );
}
return uiDLCmask;
}
void DLCHelper::AppendDLCKeyValues( KeyValues* pKeyValues, const char* fileName, const char* startDir )
{
uint64 installedDlc = GetInstalledDLCMask();
if ( installedDlc )
{
KeyValues* pDlcKeyValues = new KeyValues( "" );
char dlcFileName[128] = "";
// We need to insert _dlc[id] into the file name right before the extension
// so filename.txt should become filename_dlc1.txt
// scan backward for '.'
int dotIndex = V_strlen( fileName ) - 1;
while ( dotIndex > 0 && fileName[dotIndex] != '.' )
{
--dotIndex;
}
if ( dotIndex == 0 )
{
Warning( "Invalid file name passed to DLCHelper::AppendDLCKeyValues (%s)\n", fileName );
return;
}
const char* extension = fileName + dotIndex + 1;
V_strncpy( dlcFileName, fileName, 128 );
// For each installed dlc check for an updated file and merge it in
for ( uint64 i = 1; i < 64; i++ )
{
// Don't bother if this dlc isn't installed
if ( installedDlc & ( 1ull << i ) )
{
// Get the filename for this dlc
V_snprintf( dlcFileName + dotIndex, 128 - dotIndex, "_dlc%d.%s", ( int )i, extension );
// Load and merge the keys from this dlc
pDlcKeyValues->Clear();
if ( pDlcKeyValues->LoadFromFile( g_pFullFileSystem, dlcFileName, startDir ) )
{
pKeyValues->MergeFrom( pDlcKeyValues, KeyValues::MERGE_KV_UPDATE );
}
else
{
Warning( "Failed to load %s\n", dlcFileName );
}
}
}
if ( pDlcKeyValues )
{
pDlcKeyValues->deleteThis();
pDlcKeyValues = NULL;
}
}
}
#endif // _DLC_HELPER_H
+539
View File
@@ -0,0 +1,539 @@
//=========== Copyright Valve Corporation, All rights reserved. ==============//
#include "cbase.h"
#include "fatdemo.h"
#include "baseplayer_shared.h"
#include "cs_gamerules.h"
#include "gametypes/igametypes.h"
#ifdef CLIENT_DLL
#include "c_team.h"
#include "c_playerresource.h"
#include "c_cs_player.h"
#include "c_cs_playerresource.h"
#else
#include "team.h"
#include "cs_player.h"
#include "cs_player_resource.h"
#endif
#include "weapon_csbase.h"
#include "cs_weapon_parse.h"
#include "proto_oob.h" // For MAKE_4BYTES
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#if !defined( CSTRIKE_REL_BUILD )
// Globals
CCSFatDemoRecorder g_fatDemoRecorder;
CCSFatDemoRecorder *g_pFatDemoRecorder = &g_fatDemoRecorder;
ConVar csgo_fatdemo_enable( "csgo_fatdemo_enable", "0", FCVAR_RELEASE );
ConVar csgo_fatdemo_output( "csgo_fatdemo_output", "test.fatdem", FCVAR_RELEASE );
// The file structure is thus:
// FatDemoHeader
// for each protobuf message:
// size of message
// protobuf message
struct FatDemoHeader
{
uint32 m_magic; // Must be characters "GOML",
uint32 m_version; // Which version of the header. Protobuf mechanisms are used for the actual payloads.
};
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
void CaptureGameState( MLGameState* pOutState );
void CaptureMatchState( MLMatchState* pOutState );
void CaptureRoundState( MLRoundState* pOutState );
void CapturePlayerState( MLPlayerState* pOutState, CCSPlayer* pCsPlayer );
void CaptureWeaponState( MLWeaponState* pOutState, CWeaponCSBase* pCsWeapon, int index, CCSPlayer* pCsPlayer );
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
class CCSFatDemoEventVisitor : public IGameEventVisitor2
{
public:
CCSFatDemoEventVisitor( MLEvent* pEvent )
: m_pEvent( pEvent )
{}
// IGameEventVisitor2
virtual bool VisitString( const char* name, const char* value ) OVERRIDE
{
MLDict* pEntry = m_pEvent->add_data();
pEntry->set_key( name );
pEntry->set_val_string( value );
return true;
}
virtual bool VisitFloat( const char* name, float value ) OVERRIDE
{
MLDict* pEntry = m_pEvent->add_data();
pEntry->set_key( name );
pEntry->set_val_float( value );
return true;
}
virtual bool VisitInt( const char* name, int value ) OVERRIDE
{
MLDict* pEntry = m_pEvent->add_data();
pEntry->set_key( name );
pEntry->set_val_int( value );
return true;
}
virtual bool VisitBool( const char*name, bool value ) OVERRIDE
{
MLDict* pEntry = m_pEvent->add_data();
pEntry->set_key( name );
pEntry->set_val_int( value ? 1 : 0 );
return true;
}
private:
MLEvent* m_pEvent;
};
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
CCSFatDemoRecorder::CCSFatDemoRecorder()
: m_tickcount( -1 )
, m_bInLevel( false )
, m_pCurrentTick( NULL )
{
}
// ------------------------------------------------------------------------------------------------
CCSFatDemoRecorder::~CCSFatDemoRecorder()
{
}
// ------------------------------------------------------------------------------------------------
void CCSFatDemoRecorder::Reset()
{
// Sync up the state of our trackers with the current state of the game.
}
// ------------------------------------------------------------------------------------------------
void CCSFatDemoRecorder::FireGameEvent( IGameEvent *pEvent )
{
if ( !csgo_fatdemo_enable.GetBool() )
return;
if ( !m_pCurrentTick )
return;
MLEvent* pOutEvent = m_pCurrentTick->add_events();
pOutEvent->set_event_name( pEvent->GetName() );
CCSFatDemoEventVisitor visitor( pOutEvent );
pEvent->ForEventData( &visitor );
}
// ------------------------------------------------------------------------------------------------
void CCSFatDemoRecorder::PostInit()
{
ListenForAllGameEvents();
}
// ------------------------------------------------------------------------------------------------
void CCSFatDemoRecorder::LevelInitPreEntity()
{
BeginFile();
m_bInLevel = true;
m_tickcount = -1;
}
// ------------------------------------------------------------------------------------------------
void CCSFatDemoRecorder::LevelShutdownPostEntity()
{
#ifdef _LINUX
bool bWasInLevel = m_bInLevel;
#endif
m_bInLevel = false;
FinalizeFile();
// Clean up our temp memory.
m_tempPacketStorage.Purge();
if ( m_pCurrentTick )
{
delete m_pCurrentTick;
m_pCurrentTick = NULL;
}
// There's an ugly crash in the bowels of scaleform that makes it hard for us to tell whether
// CSGO was actually successful or not. However, at this point we have been successful, so we
// should go ahead and exit with a success code if we're in demo_quitafterplayback mode (which
// is the usual case for autonomous capture.
#ifdef _LINUX
static ConVarRef demo_quitafterplayback( "demo_quitafterplayback" );
if ( bWasInLevel && demo_quitafterplayback.GetBool() )
{
_exit( 0 );
}
#endif
}
// ------------------------------------------------------------------------------------------------
void CCSFatDemoRecorder::OnTickPre( int tickcount )
{
if ( !csgo_fatdemo_enable.GetBool() )
return;
// Guard against multiple updates in the client if we're running a demo that isn't a timedemo.
if ( m_tickcount == tickcount )
return;
if ( !m_bInLevel )
return;
if ( !m_outFile )
return;
Assert( CSGameRules() );
if ( m_pCurrentTick )
{
m_pCurrentTick->set_tick_count( tickcount );
CaptureGameState( m_pCurrentTick->mutable_state() );
OutputProtobuf( m_pCurrentTick );
// TODO: This should be serialized or written out to a queue or something.
delete m_pCurrentTick;
m_pCurrentTick = NULL;
}
// Set up the current tick for next tick. We do this here so that any events captured from now
// until then affect the next tick (since we're done with this tick).
m_pCurrentTick = new MLTick;
// We've updated for this tick now.
m_tickcount = tickcount;
}
// ------------------------------------------------------------------------------------------------
void CCSFatDemoRecorder::OutputProtobuf( ::google::protobuf::Message* pProto )
{
Assert( pProto );
int32 size = pProto->ByteSize();
int32 totalSize = size + sizeof( int32 );
m_tempPacketStorage.EnsureCapacity( totalSize );
*( ( int32* ) m_tempPacketStorage.Base() ) = size;
if ( !pProto->SerializeToArray( ( ( byte* ) m_tempPacketStorage.Base() ) + sizeof( int ), size ) )
{
Assert( !"Serialization failed for... reasons." );
return;
}
g_pFullFileSystem->Write( m_tempPacketStorage.Base(), totalSize, m_outFile );
}
// ------------------------------------------------------------------------------------------------
void CCSFatDemoRecorder::BeginFile()
{
char buffer[MAX_PATH];
V_strcpy_safe( buffer, csgo_fatdemo_output.GetString() );
V_DefaultExtension( buffer, ".fatdem", sizeof( buffer ) );
m_outFile = g_pFullFileSystem->OpenEx( buffer, "wb" );
if ( !m_outFile )
return;
FatDemoHeader header;
header.m_magic = MAKE_4BYTES( 'G', 'O', 'M', 'L' );
header.m_version = 1;
g_pFullFileSystem->Write( &header, sizeof( header ), m_outFile );
// Now the protobuf header,
MLDemoHeader protoHeader;
#ifdef CLIENT_DLL
protoHeader.set_map_name( engine->GetLevelNameShort() );
#else
protoHeader.set_map_name( gpGlobals->mapname.ToCStr() );
#endif
if ( gpGlobals->interval_per_tick != 0.0f )
protoHeader.set_tick_rate(1 / gpGlobals->interval_per_tick );
#ifdef CLIENT_DLL
protoHeader.set_version( engine->GetClientVersion() );
#else
protoHeader.set_version( engine->GetServerVersion() );
#endif
#ifndef NO_STEAM
EUniverse eUniverse = steamapicontext && steamapicontext->SteamUtils()
? steamapicontext->SteamUtils()->GetConnectedUniverse()
: k_EUniverseInvalid;
protoHeader.set_steam_universe( ( int ) eUniverse );
#else
// Pretty sure this doesn't actually work anymore.
protoHeader.set_steam_universe( -1 );
#endif
OutputProtobuf( &protoHeader );
}
// ------------------------------------------------------------------------------------------------
void CCSFatDemoRecorder::FinalizeFile()
{
if ( m_outFile )
g_pFullFileSystem->Close( m_outFile );
m_outFile = 0;
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
void CaptureGameState( MLGameState* pOutState )
{
CaptureMatchState( pOutState->mutable_match() );
CaptureRoundState( pOutState->mutable_round() );
for ( int i = 1; i < MAX_PLAYERS; ++i )
{
CCSPlayer* pPlayer = dynamic_cast< CCSPlayer* >( UTIL_PlayerByIndex( i ) );
if ( !pPlayer )
continue;
CapturePlayerState( pOutState->add_players(), pPlayer );
}
}
// ------------------------------------------------------------------------------------------------
void CaptureMatchState( MLMatchState* pOutState )
{
char const *szGameMode = g_pGameTypes->GetGameModeFromInt( g_pGameTypes->GetCurrentGameType(), g_pGameTypes->GetCurrentGameMode() );
if ( !szGameMode || !*szGameMode )
szGameMode = "custom";
pOutState->set_game_mode( szGameMode );
char const *szPhase = "warmup";
bool bActivePhase = false;
if ( !CSGameRules()->IsWarmupPeriod() )
{
bActivePhase = true;
switch ( CSGameRules()->GetGamePhase() )
{
case GAMEPHASE_HALFTIME:
szPhase = "intermission";
break;
case GAMEPHASE_MATCH_ENDED:
szPhase = "gameover";
break;
default:
szPhase = "live";
break;
}
}
pOutState->set_phase( szPhase );
if ( bActivePhase )
pOutState->set_round( CSGameRules()->GetTotalRoundsPlayed() );
int nTeams[2] = { TEAM_CT, TEAM_TERRORIST };
int nScores[ 2 ] = { 0, 0 };
for ( int j = 0; j < 2; ++j )
{
auto *pTeam = GetGlobalTeam( nTeams[ j ] );
if ( !pTeam )
continue;
#ifdef CLIENT_DLL
nScores[ j ] = pTeam->Get_Score();
#else
nScores[ j ] = pTeam->GetScore();
#endif
}
pOutState->set_score_ct( nScores[ 0 ] );
pOutState->set_score_t( nScores[ 1 ] );
}
// ------------------------------------------------------------------------------------------------
void CaptureRoundState( MLRoundState* pOutState )
{
char const *szPhase = "freezetime";
if ( !CSGameRules()->IsFreezePeriod() )
{
if ( CSGameRules()->IsRoundOver() )
szPhase = "over";
else
szPhase = "live";
}
pOutState->set_phase( szPhase );
switch ( CSGameRules()->m_iRoundWinStatus )
{
case WINNER_CT:
pOutState->set_win_team( ET_CT );
break;
case WINNER_TER:
pOutState->set_win_team( ET_Terrorist );
break;
}
if ( CSGameRules()->IsBombDefuseMap() )
{
char const *szBombState = "";
if ( CSGameRules()->m_bBombPlanted && !CSGameRules()->IsRoundOver() )
szBombState = "planted";
if ( CSGameRules()->IsRoundOver() )
{
// Check if the bomb exploded or got defused?
switch ( CSGameRules()->m_eRoundWinReason )
{
case Target_Bombed:
szBombState = "exploded";
break;
case Bomb_Defused:
szBombState = "defused";
break;
}
}
if ( *szBombState )
pOutState->set_bomb_state( szBombState );
}
}
// ------------------------------------------------------------------------------------------------
static void DemoSetVector( CMsgVector* pOutVec, const Vector& inVec )
{
Assert( pOutVec );
pOutVec->set_x( inVec.x );
pOutVec->set_y( inVec.y );
pOutVec->set_z( inVec.z );
}
// ------------------------------------------------------------------------------------------------
static void DemoSetQAngle( CMsgQAngle* pOutAng, const QAngle& inAng )
{
Assert( pOutAng );
pOutAng->set_x( inAng.x );
pOutAng->set_y( inAng.y );
pOutAng->set_z( inAng.z );
}
// ------------------------------------------------------------------------------------------------
static void DemoSetQAngleAndForward( CMsgQAngle* pOutAng, CMsgVector* pOutVec, const QAngle& inAng )
{
DemoSetQAngle( pOutAng, inAng );
Vector fwd;
AngleVectors( inAng, &fwd );
DemoSetVector( pOutVec, fwd );
}
// ------------------------------------------------------------------------------------------------
void CapturePlayerState( MLPlayerState* pOutState, CCSPlayer* pCsPlayer )
{
CSteamID steamID;
if ( pCsPlayer->GetSteamID( &steamID ) )
pOutState->set_account_id( steamID.GetAccountID() );
pOutState->set_entindex( pCsPlayer->entindex() );
pOutState->set_name( pCsPlayer->GetPlayerName() );
// pOutState->set_clan( );
pOutState->set_team( ( ETeam )( pCsPlayer->GetTeamNumber() ) );
pOutState->set_user_id( pCsPlayer->GetUserID() );
DemoSetVector( pOutState->mutable_abspos(), pCsPlayer->GetAbsOrigin() );
DemoSetQAngleAndForward( pOutState->mutable_eyeangle(), pOutState->mutable_eyeangle_fwd(), pCsPlayer->EyeAngles() );
pOutState->set_health( pCsPlayer->GetHealth() );
pOutState->set_armor( pCsPlayer->ArmorValue() );
#ifdef CLIENT_DLL
pOutState->set_flashed( clamp( pCsPlayer->m_flFlashOverlayAlpha, 0.0f, 1.0f ) );
pOutState->set_smoked( clamp( pCsPlayer->GetLastSmokeOverlayAlpha(), 0.0f, 1.0f ) );
pOutState->set_money( pCsPlayer->GetAccount() );
pOutState->set_helmet( pCsPlayer->HasHelmet() );
#else
// TODO pOutState->set_flashed( clamp( pCsPlayer->m_flFlashOverlayAlpha, 0.0f, 1.0f ) );
// TODO pOutState->set_smoked( clamp( pCsPlayer->GetLastSmokeOverlayAlpha(), 0.0f, 1.0f ) );
pOutState->set_money( pCsPlayer->m_iAccount );
pOutState->set_helmet( pCsPlayer->m_bHasHelmet );
#endif
pOutState->set_round_kills( pCsPlayer->m_iNumRoundKills );
pOutState->set_round_killhs( pCsPlayer->m_iNumRoundKillsHeadshots );
pOutState->set_defuse_kit( pCsPlayer->HasDefuser() );
float flOnFireAmount = 0.0f;
if ( ( pCsPlayer->m_fMolotovDamageTime > 0.0f ) && ( gpGlobals->curtime - pCsPlayer->m_fMolotovDamageTime < 2 ) ) // took burn damage in last two seconds
{
flOnFireAmount = ( gpGlobals->curtime - pCsPlayer->m_fMolotovDamageTime <= 1.0f )
? 1.0f
: ( 2.0f - gpGlobals->curtime + pCsPlayer->m_fMolotovDamageTime );
}
pOutState->set_burning( clamp( flOnFireAmount, 0.0f, 1.0f ) );
int numWeapons = 0;
for ( int i = 0; i < pCsPlayer->WeaponCount(); ++i )
{
CWeaponCSBase* pCsWeapon = dynamic_cast< CWeaponCSBase * >( pCsPlayer->GetWeapon( i ) );
if ( !pCsWeapon )
continue;
CaptureWeaponState( pOutState->add_weapons(), pCsWeapon, numWeapons, pCsPlayer );
++numWeapons;
}
}
// ------------------------------------------------------------------------------------------------
void CaptureWeaponState( MLWeaponState* pOutState, CWeaponCSBase* pCsWeapon, int index, CCSPlayer* pCsPlayer )
{
pOutState->set_index( index );
pOutState->set_name( pCsWeapon->GetName() );
pOutState->set_type( ( EWeaponType ) pCsWeapon->GetWeaponType() );
pOutState->set_recoil_index( pCsWeapon->m_flRecoilIndex );
if ( pCsWeapon->m_iClip1 >= 0 )
pOutState->set_ammo_clip( pCsWeapon->m_iClip1 );
int iMaxClip1 = pCsWeapon->GetMaxClip1();
if ( iMaxClip1 > 0 )
pOutState->set_ammo_clip_max( iMaxClip1 );
if ( pCsWeapon->GetPrimaryAmmoType() >= 0 )
pOutState->set_ammo_reserve( pCsWeapon->GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) );
char const *szState = "holstered";
if ( pCsPlayer->GetActiveCSWeapon() == pCsWeapon )
{
szState = "active";
if ( pCsWeapon->m_bInReload )
szState = "reloading";
}
pOutState->set_state( szState );
}
#endif
+48
View File
@@ -0,0 +1,48 @@
//=========== Copyright Valve Corporation, All rights reserved. ==============//
#pragma once
#include "GameEventListener.h"
#include "igamesystem.h"
// This is completely disabled in release builds. We overwrite client Rel DLLs with client Staging DLLs on our cluster.
#if !defined( CSTRIKE_REL_BUILD )
// Records game state to a fat demo format.
class CCSFatDemoRecorder : public CAutoGameSystem, public CGameEventListener
{
public:
CCSFatDemoRecorder();
virtual ~CCSFatDemoRecorder();
void Reset();
virtual void FireGameEvent( IGameEvent *event ) OVERRIDE;
virtual void PostInit() OVERRIDE;
virtual void LevelInitPreEntity() OVERRIDE;
virtual void LevelShutdownPostEntity() OVERRIDE;
void OnTickPre( int tickcount );
private:
void OutputProtobuf( ::google::protobuf::Message* pTick );
void BeginFile();
void FinalizeFile();
private:
CUtlString m_currentMap;
int m_tickcount;
bool m_bInLevel;
MLTick* m_pCurrentTick;
FileHandle_t m_outFile;
CUtlBuffer m_tempPacketStorage;
};
// The global to get at the instance of this class.
extern CCSFatDemoRecorder* g_pFatDemoRecorder;
#endif
@@ -0,0 +1,451 @@
//========= Copyright © 1996-2005, 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 "cs_gamerules.h"
#include "animation.h"
#define GRENADE_MODEL "models/Weapons/w_eq_flashbang_dropped.mdl"
LINK_ENTITY_TO_CLASS( flashbang_projectile, CFlashbangProjectile );
PRECACHE_REGISTER( flashbang_projectile );
#if !defined( CLIENT_DLL )
BEGIN_DATADESC( CFlashbangProjectile )
// Fields
//DEFINE_KEYFIELD( m_flTimeToDetonate, FIELD_FLOAT, "TimeToDetonate" ),
// Inputs
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetTimer", InputSetTimer ),
END_DATADESC()
#endif
// hack to allow de_nuke vents to occlude flashbangs when closed
class CTraceFilterNoPlayersAndFlashbangPassableAnims : public CTraceFilterNoPlayers
{
public:
CTraceFilterNoPlayersAndFlashbangPassableAnims( const IHandleEntity *passentity = NULL, int collisionGroup = COLLISION_GROUP_NONE )
: CTraceFilterNoPlayers( passentity, collisionGroup )
{
}
virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
{
CBaseEntity *pEnt = EntityFromEntityHandle(pHandleEntity);
if ( pEnt )
{
CBaseAnimating* pAnimating = dynamic_cast< CBaseAnimating* >( pEnt );
if ( pAnimating )
{
// look for the flashbang passable animtag
float flFlashbangPassable = pAnimating->GetAnySequenceAnimTag( pAnimating->GetSequence(), ANIMTAG_FLASHBANG_PASSABLE, -1 );
if ( flFlashbangPassable != -1 )
return false; // model animation is tagged to allow flashbangs through
}
// Weapons don't block flashbangs
CWeaponCSBase* pWeapon = dynamic_cast< CWeaponCSBase* >( pEnt );
CBaseGrenade* pGrenade = dynamic_cast< CBaseGrenade* > ( pEnt );
if ( pWeapon || pGrenade )
return false;
}
return CTraceFilterNoPlayers::ShouldHitEntity( pHandleEntity, contentsMask );
}
};
float PercentageOfFlashForPlayer(CBaseEntity *player, Vector flashPos, CBaseEntity *pevInflictor)
{
if (!(player->IsPlayer()))
{
// if this entity isn't a player, it's a hostage or some other entity, then don't bother with the expensive checks
// that come below.
return 0.0f;
}
const float FLASH_FRACTION = 0.167f;
const float SIDE_OFFSET = 75.0f;
Vector pos = player->EyePosition();
Vector vecRight, vecUp;
QAngle tempAngle;
VectorAngles(player->EyePosition() - flashPos, tempAngle);
AngleVectors(tempAngle, NULL, &vecRight, &vecUp);
vecRight.NormalizeInPlace();
vecUp.NormalizeInPlace();
// Set up all the ray stuff.
// We don't want to let other players block the flash bang so we use this custom filter.
Ray_t ray;
trace_t tr;
CTraceFilterNoPlayersAndFlashbangPassableAnims traceFilter( pevInflictor, COLLISION_GROUP_NONE );
unsigned int FLASH_MASK = MASK_OPAQUE_AND_NPCS | CONTENTS_DEBRIS;
// According to comment in IsNoDrawBrush in cmodel.cpp, CONTENTS_OPAQUE is ONLY used for block light surfaces,
// and we want flashbang traces to pass through those, since the block light surface is only used for blocking
// lightmap light rays during map compilation.
FLASH_MASK &= ~CONTENTS_OPAQUE;
ray.Init( flashPos, pos );
enginetrace->TraceRay( ray, FLASH_MASK, &traceFilter, &tr );
if ((tr.fraction == 1.0f) || (tr.m_pEnt == player))
{
return 1.0f;
}
float retval = 0.0f;
// check the point straight up.
pos = flashPos + vecUp*50.0f;
ray.Init( flashPos, pos );
enginetrace->TraceRay( ray, FLASH_MASK, &traceFilter, &tr );
// Now shoot it to the player's eye.
pos = player->EyePosition();
ray.Init( tr.endpos, pos );
enginetrace->TraceRay( ray, FLASH_MASK, &traceFilter, &tr );
if ((tr.fraction == 1.0f) || (tr.m_pEnt == player))
{
retval += FLASH_FRACTION;
}
// check the point up and right.
pos = flashPos + vecRight*SIDE_OFFSET + vecUp*10.0f;
ray.Init( flashPos, pos );
enginetrace->TraceRay( ray, FLASH_MASK, &traceFilter, &tr );
// Now shoot it to the player's eye.
pos = player->EyePosition();
ray.Init( tr.endpos, pos );
enginetrace->TraceRay( ray, FLASH_MASK, &traceFilter, &tr );
if ((tr.fraction == 1.0f) || (tr.m_pEnt == player))
{
retval += FLASH_FRACTION;
}
// Check the point up and left.
pos = flashPos - vecRight*SIDE_OFFSET + vecUp*10.0f;
ray.Init( flashPos, pos );
enginetrace->TraceRay( ray, FLASH_MASK, &traceFilter, &tr );
// Now shoot it to the player's eye.
pos = player->EyePosition();
ray.Init( tr.endpos, pos );
enginetrace->TraceRay( ray, FLASH_MASK, &traceFilter, &tr );
if ((tr.fraction == 1.0f) || (tr.m_pEnt == player))
{
retval += FLASH_FRACTION;
}
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,
uint8 *pOutNumOpponentsEffected = NULL,
uint8 *pOutNumTeammatesEffected = NULL )
{
vecSrc.z += 1;// in case grenade is lying on the ground
if ( !pevAttacker )
pevAttacker = pevInflictor;
if ( pOutNumOpponentsEffected )
*pOutNumOpponentsEffected = 0;
if ( pOutNumTeammatesEffected )
*pOutNumTeammatesEffected = 0;
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 = 3000;
float falloff = flDamage / flRadius;
//bool bInWater = (UTIL_PointContents( vecSrc, MASK_WATER ) == CONTENTS_WATER);
// iterate on all entities in the vicinity.
while ((pEntity = gEntList.FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL)
{
bool bPlayer = pEntity->IsPlayer();
if( !bPlayer )
continue;
vecEyePos = pEntity->EyePosition();
//// blasts used to not travel into or out of water, users assumed it was a bug. Fix is not to run this check -wills
//if ( bInWater && pEntity->GetWaterLevel() == WL_NotInWater)
// continue;
//if (!bInWater && pEntity->GetWaterLevel() == WL_Eyes)
// continue;
float percentageOfFlash = PercentageOfFlashForPlayer(pEntity, vecSrc, pevInflictor);
if ( percentageOfFlash > 0.0 )
{
if ( pOutNumOpponentsEffected && pEntity->GetTeamNumber() != pevAttacker->GetTeamNumber() )
(*pOutNumOpponentsEffected)++;
if ( pOutNumTeammatesEffected && pEntity->GetTeamNumber() == pevAttacker->GetTeamNumber() )
(*pOutNumTeammatesEffected)++;
// 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();
//DebugDrawLine( vecEyePos, vecEyePos + (100.0 * vecLOS), 0, 255, 0, true, 10.0 );
//DebugDrawLine( vecEyePos, vecEyePos + (100.0 * vForward), 0, 0, 255, true, 10.0 );
// 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.6 )
{
// looking at the flashbang
fadeTime = flAdjustedDamage * 2.5f;
fadeHold = flAdjustedDamage * 1.25f;
}
else if( flDot >= 0.3 )
{
// looking to the side
fadeTime = flAdjustedDamage * 1.75f;
fadeHold = flAdjustedDamage * 0.8f;
}
else if( flDot >= -0.2 )
{
// looking to the side
fadeTime = flAdjustedDamage * 1.00f;
fadeHold = flAdjustedDamage * 0.5f;
}
else
{
// facing away
fadeTime = flAdjustedDamage * 0.5f;
fadeHold = flAdjustedDamage * 0.25f;
// startingAlpha = 200;
}
fadeTime *= percentageOfFlash;
fadeHold *= percentageOfFlash;
if ( bPlayer )
{
// blind players and bots
CCSPlayer *player = static_cast< CCSPlayer * >( pEntity );
// [tj] Store who was responsible for the most recent flashbang blinding.
CCSPlayer *attacker = ToCSPlayer (pevAttacker);
if ( attacker && player && player->IsAlive() )
{
player->SetLastFlashbangAttacker(attacker);
// score points/penalties for blinding players
if ( flDot >= 0.0f )
{
if ( attacker->GetTeamNumber() == player->GetTeamNumber() )
CSGameRules()->ScoreBlindFriendly( attacker );
else
CSGameRules()->ScoreBlindEnemy( attacker );
}
}
player->Blind( fadeHold, fadeTime, startingAlpha );
// fire an event when a player has been sufficiently blinded as to not
// be able to perform the training map flashbang range test
if ( CSGameRules()->IsPlayingTraining() && fadeHold > 1.9f )
{
IGameEvent * event = gameeventmanager->CreateEvent( "tr_player_flashbanged" );
if ( event )
{
event->SetInt( "userid", player->GetUserID() );
gameeventmanager->FireEvent( event );
}
}
IGameEvent * event = gameeventmanager->CreateEvent( "player_blind" );
if ( event )
{
event->SetInt( "userid", player->GetUserID() );
event->SetInt( "attacker", attacker ? attacker->GetUserID() : 0 );
event->SetInt( "entityid", pevInflictor ? pevInflictor->entindex() : 0 );
event->SetFloat( "blind_duration", player->m_flFlashDuration );
gameeventmanager->FireEvent( event );
}
// deafen players and bots
player->Deafen( flDistance );
}
}
}
}
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,
const CCSWeaponInfo& weaponInfo )
{
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_pWeaponInfo = &weaponInfo;
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
pGrenade->ApplyLocalAngularVelocityImpulse( angVelocity );
pGrenade->SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
return pGrenade;
}
CFlashbangProjectile::CFlashbangProjectile()
{
m_flDamage = 100;
// default timer value for when a player throws it
// can be overridden when spawned from an entity maker
m_flTimeToDetonate = 1.5;
m_numOpponentsHit = m_numTeammatesHit = 0;
}
void CFlashbangProjectile::Spawn()
{
SetModel( GRENADE_MODEL );
SetDetonateTimerLength( m_flTimeToDetonate );
SetTouch( &CBaseGrenade::BounceTouch );
SetThink( &CBaseCSGrenadeProjectile::DangerSoundThink );
SetNextThink( gpGlobals->curtime );
SetGravity( BaseClass::GetGrenadeGravity() );
SetFriction( BaseClass::GetGrenadeFriction() );
SetElasticity( BaseClass::GetGrenadeElasticity() );
m_pWeaponInfo = GetWeaponInfo( WEAPON_FLASHBANG );
BaseClass::Spawn();
SetBodygroupPreset( "thrown" );
}
void CFlashbangProjectile::Precache()
{
PrecacheModel( GRENADE_MODEL );
PrecacheScriptSound( "Flashbang.Explode" );
PrecacheScriptSound( "Flashbang.Bounce" );
BaseClass::Precache();
}
ConVar sv_flashbang_strength( "sv_flashbang_strength", "3.55", FCVAR_REPLICATED, "Flashbang strength", true, 2.0, true, 8.0 );
void CFlashbangProjectile::Detonate()
{
// tell the bots a flashbang grenade has exploded (and record log events)
CCSPlayer *player = ToCSPlayer( GetThrower() );
if ( player )
{
IGameEvent * event = gameeventmanager->CreateEvent( "flashbang_detonate" );
if ( event )
{
event->SetInt( "userid", player->GetUserID() );
event->SetInt( "entityid", this->entindex() );
event->SetFloat( "x", GetAbsOrigin().x );
event->SetFloat( "y", GetAbsOrigin().y );
event->SetFloat( "z", GetAbsOrigin().z );
gameeventmanager->FireEvent( event );
}
}
RadiusFlash ( GetAbsOrigin(), this, GetThrower(), sv_flashbang_strength.GetInt(), CLASS_NONE, DMG_BLAST, &m_numOpponentsHit, &m_numTeammatesHit );
EmitSound( "Flashbang.Explode" );
trace_t tr;
Vector vecSpot = GetAbsOrigin() + Vector ( 0 , 0 , 2 );
UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -64 ), MASK_SHOT_HULL, this, COLLISION_GROUP_NONE, & tr);
UTIL_DecalTrace( &tr, "Scorch" );
// Because we don't chain to base, tell ogs to record this detonation here
RecordDetonation();
UTIL_Remove( this );
}
//TODO: Let physics handle the sound!
void CFlashbangProjectile::BounceSound( void )
{
EmitSound( "Flashbang.Bounce" );
}
void CFlashbangProjectile::InputSetTimer( inputdata_t &inputdata )
{
m_flTimeToDetonate = inputdata.value.Float();
SetDetonateTimerLength( m_flTimeToDetonate );
}
@@ -0,0 +1,57 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef FLASHBANG_PROJECTILE_H
#define FLASHBANG_PROJECTILE_H
#ifdef _WIN32
#pragma once
#endif
#include "basecsgrenade_projectile.h"
class CFlashbangProjectile : public CBaseCSGrenadeProjectile
{
public:
DECLARE_CLASS( CFlashbangProjectile, CBaseCSGrenadeProjectile );
#if !defined( CLIENT_DLL )
DECLARE_DATADESC();
#endif
// Overrides.
public:
CFlashbangProjectile();
virtual void Spawn();
virtual void Precache();
virtual void BounceSound( void );
virtual void Detonate();
void InputSetTimer( inputdata_t &inputdata );
virtual GrenadeType_t GetGrenadeType( void ) { return GRENADE_TYPE_FLASH; }
// Grenade stuff.
static CFlashbangProjectile* Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
const CCSWeaponInfo& weaponInfo );
public:
float m_flTimeToDetonate;
// Count of players effected by the flash
uint8 m_numOpponentsHit; // note: opponents are considered to be anybody not on the flasher's team.
uint8 m_numTeammatesHit;
};
#endif // FLASHBANG_PROJECTILE_H
+618
View File
@@ -0,0 +1,618 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "fx_cs_shared.h"
#include "weapon_csbase.h"
#include "rumble_shared.h"
#ifndef CLIENT_DLL
#include "ilagcompensationmanager.h"
#endif
ConVar weapon_accuracy_logging( "weapon_accuracy_logging", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY | FCVAR_ARCHIVE );
ConVar steam_controller_haptics( "steam_controller_haptics", "1", FCVAR_RELEASE );
ConVar weapon_near_empty_sound( "weapon_near_empty_sound", "1", FCVAR_REPLICATED | FCVAR_CHEAT );
ConVar weapon_debug_max_inaccuracy( "weapon_debug_max_inaccuracy", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT, "Force all shots to have maximum inaccuracy" );
ConVar weapon_debug_inaccuracy_only_up( "weapon_debug_inaccuracy_only_up", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT, "Force weapon inaccuracy to be in exactly the up direction" );
ConVar snd_max_pitch_shift_inaccuracy("snd_max_pitch_shift_inaccuracy", "0.08", 0);
#ifdef CLIENT_DLL
#include "fx_impact.h"
#include "c_rumble.h"
#include "inputsystem/iinputsystem.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
// this is a cheap ripoff from CBaseCombatWeapon::WeaponSound():
void FX_WeaponSound(
int iPlayerIndex,
uint16 nItemDefIndex,
WeaponSound_t sound_type,
const Vector &vOrigin,
const CCSWeaponInfo *pWeaponInfo,
float flSoundTime,
int nPitch )
{
// If we have some sounds from the weapon classname.txt file, play a random one of them
const char *shootsound = pWeaponInfo->aShootSounds[ sound_type ];
// Get the item definition
const CEconItemDefinition *pDef = ( nItemDefIndex > 0 ) ? GetItemSchema()->GetItemDefinition( nItemDefIndex ) : NULL;
if ( pDef )
{
const char *pszTempSound = pDef->GetWeaponReplacementSound( sound_type );
if ( pszTempSound )
{
shootsound = pszTempSound;
}
}
if ( !shootsound || !shootsound[0] )
return;
CBroadcastRecipientFilter filter; // this is client side only
if ( !te->CanPredict() )
return;
EmitSound_t params;
params.m_pSoundName = shootsound;
params.m_flSoundTime = flSoundTime;
params.m_pOrigin = &vOrigin;
params.m_pflSoundDuration = nullptr;
params.m_bWarnOnDirectWaveReference = true;
params.m_nPitch = nPitch;
if (nPitch != PITCH_NORM)
{
params.m_nFlags = params.m_nFlags | SND_OVERRIDE_PITCH;
}
CBaseEntity::EmitSound( filter, iPlayerIndex, params );
}
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,
uint16 nItemDefIndex,
WeaponSound_t sound_type,
const Vector &vOrigin,
const CCSWeaponInfo *pWeaponInfo, float flSoundTime, int nPitch ) {};
#endif
ConVar debug_aim_angle("debug_aim_angle", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY);
// 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,
uint16 nItemDefIndex,
const Vector &vOrigin,
const QAngle &vAngles,
CSWeaponID iWeaponID,
int iMode,
int iSeed,
float fInaccuracy,
float fSpread,
float fAccuracyFishtail,
float flSoundTime,
WeaponSound_t sound_type,
float flRecoilIndex
)
{
bool bDoEffects = true;
if ( fInaccuracy > 1.0f )
fInaccuracy = 1.0f;
#ifdef CLIENT_DLL
C_CSPlayer *pPlayer = ToCSPlayer( ClientEntityList().GetBaseEntity( iPlayerIndex ) );
#else
CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( iPlayerIndex) );
#endif
if ( !pPlayer || iPlayerIndex < 0 )
{
// probably an env_gunfire
const CCSWeaponInfo* pWeaponInfo = GetWeaponInfo( iWeaponID );
FX_WeaponSound( iPlayerIndex, nItemDefIndex, sound_type, vOrigin, pWeaponInfo, flSoundTime, PITCH_NORM );
#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(
-1,
nItemDefIndex,
vOrigin,
vAngles,
iWeaponID,
iMode,
iSeed,
fInaccuracy,
fSpread,
fAccuracyFishtail,
sound_type,
flRecoilIndex
);
#endif
return;
}
#ifdef CLIENT_DLL
CWeaponCSBase* pClientWeapon = pPlayer ? pPlayer->GetActiveCSWeapon() : NULL;
if ( pClientWeapon )
{
if ( gpGlobals->curtime - pClientWeapon->m_flLastClientFireBulletTime > 0.02f ) // this should be enough even for the negev, at ~1000 rof
{
pClientWeapon->m_flLastClientFireBulletTime = gpGlobals->curtime;
}
else
{
return; // we already traced this shot on the client!
}
}
#endif
QAngle adjustedAngles = vAngles;
adjustedAngles.y += fAccuracyFishtail;
if ( pPlayer && debug_aim_angle.GetBool() )
{
QAngle old = pPlayer->EyeAngles() + pPlayer->GetAimPunchAngle();
#ifdef CLIENT_DLL
DevMsg("Client ");
#else
DevMsg("Server ");
#endif
DevMsg("old: %f %f new: %f %f\n",
old[YAW], old[PITCH],
vAngles[YAW], vAngles[PITCH]
);
if ( debug_aim_angle.GetInt() == 2 )
{
adjustedAngles = old;
}
}
const CEconItemDefinition* pItemDef = GetItemSchema()->GetItemDefinition( nItemDefIndex );
if ( !pItemDef )
{
DevMsg( "FX_FireBullets: GetItemDefinition failed for defindex %d\n", nItemDefIndex );
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, pItemDef->GetItemBaseName(), fInaccuracy, fSpread, fInaccuracy + fSpread, iMode, fVelocity, iSeed, szFlags);
}
#endif
WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( pItemDef->GetItemClass() );
if ( hWpnInfo == GetInvalidWeaponInfoHandle() )
{
DevMsg("FX_FireBullets: LookupWeaponInfoSlot failed for weapon %s\n", pItemDef->GetItemBaseName() );
return;
}
CCSWeaponInfo *pWeaponInfo = static_cast< CCSWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
if ( !pWeaponInfo )
{
DevMsg( "FX_FireBullets: GetFileWeaponInfoFromHandle failed for weapon %s\n", pItemDef->GetItemBaseName() );
return;
}
// Do the firing animation event.
#ifndef CLIENT_DLL
if ( pPlayer && !pPlayer->IsDormant() )
{
if ( iMode == Primary_Mode )
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_PRIMARY );
else
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_SECONDARY );
}
#endif // CLIENT_DLL
#ifdef CLIENT_DLL
if ( pPlayer && pPlayer->m_bUseNewAnimstate )
{
pPlayer->ProcessMuzzleFlashEvent();
}
#endif
#ifndef CLIENT_DLL
// if this is server code, send the effect over to client as temp entity
// Dispatch one message for all the bullet impacts and sounds.
TE_FireBullets(
iPlayerIndex,
nItemDefIndex,
vOrigin,
vAngles,
iWeaponID,
iMode,
iSeed,
fInaccuracy,
fSpread,
fAccuracyFishtail,
sound_type,
flRecoilIndex
);
// Let the player remember the usercmd he fired a weapon on. Assists in making decisions about lag compensation.
if ( pPlayer )
pPlayer->NoteWeaponFired();
bDoEffects = false; // no effects on server
#endif
iSeed++;
CWeaponCSBase* pWeapon = pPlayer ? pPlayer->GetActiveCSWeapon() : NULL;
CEconItemView* pItem = pWeapon ? pWeapon->GetEconItemView() : NULL;
int iDamage = pWeaponInfo->GetDamage( pItem );
float flRange = pWeaponInfo->GetRange( pItem );
float flPenetration = pWeaponInfo->GetPenetration( pItem );
float flRangeModifier = pWeaponInfo->GetRangeModifier( pItem );
int iAmmoType = pWeaponInfo->GetPrimaryAmmoType( pItem );
if ( bDoEffects)
{
static const float MaxPitchShiftInaccuracy = 0.05f;
float flPitchShift = pWeaponInfo->GetInaccuracyPitchShift() * (fInaccuracy < MaxPitchShiftInaccuracy ? fInaccuracy : MaxPitchShiftInaccuracy);
if ( sound_type == SINGLE && pWeaponInfo->GetInaccuracyAltSoundThreshhold() > 0.0f && fInaccuracy < pWeaponInfo->GetInaccuracyAltSoundThreshhold() )
{
sound_type = SINGLE_ACCURATE;
flPitchShift = 0.0f;
}
FX_WeaponSound( iPlayerIndex, nItemDefIndex, sound_type, vOrigin, pWeaponInfo, flSoundTime, PITCH_NORM + int(flPitchShift) );
// If the gun's nearly empty, also play a subtle "nearly-empty" sound, since the weapon
// is lighter and acoustically different when weighed down by fewer bullets.
// But really it's so you get a fun low ammo warning from an audio cue.
if ( weapon_near_empty_sound.GetBool() &&
pWeapon && pWeapon->GetMaxClip1() > 1 && // not a single-shot weapon
(((float)pWeapon->m_iClip1) / ((float)pWeapon->GetMaxClip1()) <= 0.2) ) // 20% or fewer bullets remaining
{
FX_WeaponSound( iPlayerIndex, nItemDefIndex, NEARLYEMPTY, vOrigin, pWeaponInfo, flSoundTime, PITCH_NORM );
}
}
// 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, LAG_COMPENSATE_HITBOXES_ALONG_RAY, vOrigin, vAngles, flRange );
#endif
// [sbodenbender] rumble when shooting
// since we are handling bullet fx in CS differently than other titles, call
// rumble effect directly instead of Player::RumbleEffect
//=============================================================================
#if defined (CLIENT_DLL)
if (pPlayer && pPlayer->IsLocalPlayer() && pWeaponInfo && pWeaponInfo->GetBullets() > 0)
{
int rumbleEffect = pWeaponInfo->iRumbleEffect;
if( rumbleEffect != RUMBLE_INVALID )
{
RumbleEffect( XBX_GetUserId( pPlayer->GetSplitScreenPlayerSlot() ), rumbleEffect, 0, RUMBLE_FLAG_RESTART );
}
if ( rumbleEffect != RUMBLE_INVALID && rumbleEffect <= 6 && steam_controller_haptics.GetBool() && g_pInputSystem->IsSteamControllerActive() && steamapicontext->SteamController() )
{
ControllerHandle_t handles[MAX_STEAM_CONTROLLERS];
int nControllers = steamapicontext->SteamController()->GetConnectedControllers( handles );
for ( int i = 0; i < nControllers; ++i )
{
steamapicontext->SteamController()->TriggerHapticPulse( handles[ i ], k_ESteamControllerPad_Right, (2000*rumbleEffect)/5 );
steamapicontext->SteamController()->TriggerHapticPulse( handles[ i ], k_ESteamControllerPad_Left, (2000*rumbleEffect)/5 );
}
}
}
#endif
bool bForceMaxInaccuracy = weapon_debug_max_inaccuracy.GetBool();
bool bForceInaccuracyDirection = weapon_debug_inaccuracy_only_up.GetBool();
RandomSeed( iSeed ); // init random system with this seed
// Accuracy curve density adjustment FOR R8 REVOLVER SECONDARY FIRE, NEGEV WILD BEAST
float flRadiusCurveDensity = RandomFloat();
if ( nItemDefIndex == 64 && iMode == Secondary_Mode ) /*R8 REVOLVER SECONDARY FIRE*/
{
flRadiusCurveDensity = 1.0f - flRadiusCurveDensity*flRadiusCurveDensity;
}
if ( nItemDefIndex == 28 && flRecoilIndex < 3 ) /*NEGEV WILD BEAST*/
{
for ( int j = 3; j > flRecoilIndex; -- j )
{
flRadiusCurveDensity *= flRadiusCurveDensity;
}
flRadiusCurveDensity = 1.0f - flRadiusCurveDensity;
}
if ( bForceMaxInaccuracy )
flRadiusCurveDensity = 1.0f;
// Get accuracy displacement
float fTheta0 = RandomFloat(0.0f, 2.0f * M_PI);
if ( bForceInaccuracyDirection )
fTheta0 = M_PI * 0.5f;
float fRadius0 = flRadiusCurveDensity * fInaccuracy;
float x0 = fRadius0 * cosf(fTheta0);
float y0 = fRadius0 * sinf(fTheta0);
const int kMaxBullets = 16;
float x1[kMaxBullets], y1[kMaxBullets];
Assert(pWeaponInfo->GetBullets() <= kMaxBullets);
// the RNG can be desynchronized by FireBullet(), so pre-generate all spread offsets
for ( int iBullet=0; iBullet < pWeaponInfo->GetBullets(); iBullet++ )
{
// Spread curve density adjustment for R8 REVOLVER SECONDARY FIRE, NEGEV WILD BEAST
float flSpreadCurveDensity = RandomFloat();
if ( nItemDefIndex == 64 && iMode == Secondary_Mode )
{
flSpreadCurveDensity = 1.0f - flSpreadCurveDensity*flSpreadCurveDensity;
}
if ( nItemDefIndex == 28 && flRecoilIndex < 3 ) /*NEGEV WILD BEAST*/
{
for ( int j = 3; j > flRecoilIndex; --j )
{
flSpreadCurveDensity *= flSpreadCurveDensity;
}
flSpreadCurveDensity = 1.0f - flSpreadCurveDensity;
}
if ( bForceMaxInaccuracy )
flSpreadCurveDensity = 1.0f;
float fTheta1 = RandomFloat(0.0f, 2.0f * M_PI);
if ( bForceInaccuracyDirection )
fTheta1 = M_PI * 0.5f;
float fRadius1 = flSpreadCurveDensity * fSpread;
x1[iBullet] = fRadius1 * cosf(fTheta1);
y1[iBullet] = fRadius1 * sinf(fTheta1);
}
#if !defined( CLIENT_DLL )
{ /// Make sure take damage listener stays in scope only for the duration of FireBullet loop below!
class CFireBulletTakeDamageListener : public CCSPlayer::ITakeDamageListener
{
public:
CFireBulletTakeDamageListener( CCSPlayer *pPlayerShooting ) :
m_pPlayerShooting(pPlayerShooting),
m_bEnemyHit( false ),
m_bShotFiredAndOnTargetRecorded( false )
{}
virtual void OnTakeDamageListenerCallback( CCSPlayer *pVictim, CTakeDamageInfo &infoTweakable ) OVERRIDE
{
if ( m_pPlayerShooting && pVictim->IsOtherEnemy( m_pPlayerShooting ) )
{
m_bEnemyHit = true;
if ( infoTweakable.GetDamageType() & DMG_HEADSHOT )
{
m_rbHsPlayers.InsertIfNotFound( pVictim ); // remember that at least one pellet hit a headshot
}
else if ( m_rbHsPlayers.Find( pVictim ) != m_rbHsPlayers.InvalidIndex() )
{
#if 0
DevMsg( "DMG: Pellet modified for headshot visualization %s -> %s = (0x%08X +hs)\n",
m_pPlayerShooting ? m_pPlayerShooting->GetPlayerName() : "[unknown]",
pVictim->GetPlayerName(), infoTweakable.GetDamageType() );
#endif
infoTweakable.SetDamageType( infoTweakable.GetDamageType() | DMG_HEADSHOT ); // since previous pellets hit a headshot we visualize it as a headshot
}
// Since we know that bullet was fired and that we hit the target
// we should record the accuracy stats right now, otherwise we may TerminateRound
// based on a kill from this bullet and not have this data recorded
RecordShotFiredAndOnTargetData();
}
}
void BulletBurstCompleted()
{
RecordShotFiredAndOnTargetData();
}
private:
void RecordShotFiredAndOnTargetData()
{
if ( m_bShotFiredAndOnTargetRecorded )
return;
m_bShotFiredAndOnTargetRecorded = true;
if ( m_pPlayerShooting && CSGameRules() && !CSGameRules()->IsWarmupPeriod() && !m_pPlayerShooting->IsBot() )
{
// Track in QMM total number of shots that connected with an opponent
if ( CCSGameRules::CQMMPlayerData_t *pQMM = CSGameRules()->QueuedMatchmakingPlayersDataFind( m_pPlayerShooting->GetHumanPlayerAccountID() ) )
{
++pQMM->m_numShotsFiredTotal;
if ( m_bEnemyHit )
++pQMM->m_numShotsOnTargetTotal;
}
}
}
private:
CCSPlayer *m_pPlayerShooting;
bool m_bEnemyHit;
bool m_bShotFiredAndOnTargetRecorded;
CUtlRBTree< CCSPlayer *, int, CDefLess< CCSPlayer * > > m_rbHsPlayers; // players who were dinked in the head as part of this bullet batch
} fbtdl( pPlayer );
#endif
for ( int iBullet=0; iBullet < pWeaponInfo->GetBullets(); iBullet++ )
{
if ( !pPlayer )
break;
int nPenetrationCount = 4;
pPlayer->FireBullet(
vOrigin,
adjustedAngles,
flRange,
flPenetration,
nPenetrationCount,
iAmmoType,
iDamage,
flRangeModifier,
pPlayer,
bDoEffects,
x0 + x1[iBullet], y0 + y1[iBullet]
);
}
#if !defined( CLIENT_DLL )
fbtdl.BulletBurstCompleted();
} /// Closes the lifetime scope of take damage listener in scope only for the duration of FireBullet loop above.
#endif
#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->DoAnimStateEvent( PLAYERANIMEVENT_FIRE_GUN_PRIMARY );
}
break;
case PLANTBOMB_ABORT:
{
pPlayer->DoAnimStateEvent( 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
}
+51
View File
@@ -0,0 +1,51 @@
//========= Copyright © 1996-2005, 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,
uint16 nItemDefIndex,
const Vector &vOrigin,
const QAngle &vAngles,
CSWeaponID iWeaponID,
int iMode,
int iSeed,
float fInaccuracy,
float fSpread,
float fAccuracyFishtail,
float flSoundTime/* = 0.0f*/,
WeaponSound_t sound_type/* = SINGLE*/,
float flRecoilIndex/* = 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
File diff suppressed because it is too large Load Diff
+341
View File
@@ -0,0 +1,341 @@
//========= Copyright (c) 1996-2011, Valve Corporation, All rights reserved. ============//
//
// Purpose: Game types and modes
//
// $NoKeywords: $
//=============================================================================//
#ifndef GAME_TYPES_H
#define GAME_TYPES_H
#ifdef _WIN32
#pragma once
#endif
#include "gametypes/igametypes.h"
#include "tier1/keyvalues.h"
#include "const.h"
#define GAMETYPES_MAX_NAME 64
#define GAMETYPES_MAX_ID 64
#define GAMETYPES_MAX_MAP_NAME 32
#define GAMETYPES_MAX_MAP_GROUP_NAME 32
#define GAMETYPES_MAX_IMAGE_NAME 64
// enum for "game_type" convar.
// Note: these values match the order of the game types in GameModes.txt
enum CS_GameType
{
CS_GameType_Min = 0,
CS_GameType_Classic = CS_GameType_Min, // Casual and competitive (see gamerules_*.cfg)
CS_GameType_GunGame, // Arms race
CS_GameType_Training, // training map - just one map in this mode
CS_GameType_Custom, // capture the flag and such, set by map; not supported by matchmaking, supported through workshop, there are very few maps that use this game mode
CS_GameType_Cooperative, // players vs bots - matchmade, operation missions
CS_GameType_Max = CS_GameType_Cooperative
};
// enums for "game_mode" convar.
// Note: these values match the order of the game modes by type in GameModes.txt
// Note: if you add or delete a mode that you want to track ELO rankings for,
// you need to update inc_playerrankings_usr.inc to reflect the total
// number of modes that are ELO ranked
namespace CS_GameMode
{
enum Classic
{
Classic_Min = 0,
Classic_Casual = Classic_Min,
Classic_Competitive,
Classic_Competitive_Unranked,
Classic_Max = Classic_Competitive_Unranked
};
enum GunGame
{
GunGame_Min = 0,
GunGame_Progressive = GunGame_Min,
GunGame_Bomb,
GunGame_Deathmatch,
GunGame_Max = GunGame_Deathmatch
};
enum Training
{
Training_Min = 0,
Training_Training = Training_Min,
Training_Max = Training_Training
};
enum Custom
{
Custom_Min = 0,
Custom_Custom = Custom_Min,
Custom_Max = Custom_Custom
};
enum Cooperative
{
Cooperative_Min = 0,
Cooperative_Guardian = Cooperative_Min,
Cooperative_Mission,
Cooperative_Max = Cooperative_Mission
};
};
class GameTypes : public IGameTypes
{
private:
struct GameType;
struct GameMode;
struct Map;
struct MapGroup;
struct CustomBotDifficulty;
public:
GameTypes();
virtual ~GameTypes();
// Initialization
virtual bool Initialize( bool force = false );
virtual bool IsInitialized( void ) const { return m_Initialized; };
//
// Game Types and Modes
//
// Set the game type and mode convars from the given strings.
virtual bool SetGameTypeAndMode( const char *gameType, const char *gameMode );
virtual bool GetGameTypeAndModeFromAlias( const char *modeAlias, int& iOutGameType, int& iOutGameMode );
virtual bool SetGameTypeAndMode( int nGameType, int nGameMode );
virtual void SetAndParseExtendedServerInfo( KeyValues *pExtendedServerInfo );
virtual void CheckShouldSetDefaultGameModeAndType( const char* szMapNameFull );
// Get the indexes for the current game type and mode.
virtual int GetCurrentGameType() const;
virtual int GetCurrentGameMode() const;
virtual const char *GetCurrentMapName() { return m_pServerMap ? m_pServerMap->m_Name : ""; }
// Get the current game type and mode UI strings.
virtual const char *GetCurrentGameTypeNameID( void );
virtual const char *GetCurrentGameModeNameID( void );
// Apply the game mode convars for the current game type and mode.
virtual bool ApplyConvarsForCurrentMode( bool isMultiplayer );
// Output the values of the convars for the current game mode.
virtual void DisplayConvarsForCurrentMode( void );
// Returns the weapon progression for the current game type and mode.
virtual const CUtlVector< IGameTypes::WeaponProgression > *GetWeaponProgressionForCurrentModeCT( void );
virtual const CUtlVector< IGameTypes::WeaponProgression > *GetWeaponProgressionForCurrentModeT( void );
virtual int GetNoResetVoteThresholdForCurrentModeCT( void );
virtual int GetNoResetVoteThresholdForCurrentModeT( void );
virtual const char *GetGameTypeFromInt( int gameType );
virtual const char *GetGameModeFromInt( int gameType, int gameMode );
virtual bool GetGameModeAndTypeIntsFromStrings( const char* szGameType, const char* szGameMode, int& iOutGameType, int& iOutGameMode );
virtual bool GetGameModeAndTypeNameIdsFromStrings( const char* szGameType, const char* szGameMode, const char*& szOutGameTypeNameId, const char*& szOutGameModeNameId );
virtual bool GetGameTypeFromMode( const char *szGameMode, const char *&pszGameTypeOut );
//
// Maps
//
virtual const char *GetRandomMapGroup( const char *gameType, const char *gameMode );
virtual const char *GetFirstMap( const char *mapGroup );
virtual const char *GetRandomMap( const char *mapGroup );
virtual const char *GetNextMap( const char *mapGroup, const char *mapName );
virtual int GetMaxPlayersForTypeAndMode( int iType, int iMode );
virtual int GetCurrentServerNumSlots( void );
virtual int GetCurrentServerSettingInt( const char *szSetting, int iDefaultValue = 0 );
virtual bool IsValidMapGroupName( const char * mapGroup );
virtual bool IsValidMapInMapGroup( const char * mapGroup, const char *mapName );
virtual bool IsValidMapGroupForTypeAndMode( const char * mapGroup, const char *gameType, const char *gameMode );
// Apply the convars for the given map.
virtual bool ApplyConvarsForMap( const char *mapName, bool isMultiplayer );
// Get specifics about a map.
virtual bool GetMapInfo( const char *mapName, uint32 &richPresence );
// Returns the available character model names (T or CT) for the given map.
virtual const CUtlStringList *GetTModelsForMap( const char *mapName );
virtual const CUtlStringList *GetCTModelsForMap( const char *mapName );
virtual const CUtlStringList *GetHostageModelsForMap( const char *mapName );
virtual const int GetDefaultGameTypeForMap( const char *mapName );
virtual const int GetDefaultGameModeForMap( const char *mapName );
// Returns the view model arms name (T or CT) for the given map.
virtual const char *GetTViewModelArmsForMap( const char *mapName );
virtual const char *GetCTViewModelArmsForMap( const char *mapName );
// Item requirements for the map
virtual const char *GetRequiredAttrForMap( const char *mapName );
virtual int GetRequiredAttrValueForMap( const char *mapName );
virtual const char *GetRequiredAttrRewardForMap( const char *mapName );
virtual int GetRewardDropListForMap( const char *mapName );
// Map group properties
virtual const CUtlStringList *GetMapGroupMapList( const char *mapGroup );
// Make a new map group.
virtual bool CreateOrUpdateWorkshopMapGroup( const char* szName, const CUtlStringList & vecMapNames );
virtual bool IsWorkshopMapGroup( const char* szMapGroupName );
//
// Custom Bot Difficulty
//
// Sets the bot difficulty for Offline games.
virtual bool SetCustomBotDifficulty( int botDiff );
// Returns the bot difficulty for Offline games.
virtual int GetCustomBotDifficulty( void );
virtual bool LoadMapEntry( KeyValues *pKV );
private:
void InitMapSidecars( KeyValues *pKV );
void AddMapKVs( KeyValues* pKVMaps, const char* curMap );
bool LoadGameTypes( KeyValues *pKV );
bool LoadMaps( KeyValues *pKV );
bool LoadMapGroups( KeyValues *pKV );
bool LoadCustomBotDifficulties( KeyValues *pKV );
void LoadWeaponProgression( KeyValues * pKV_WeaponProgression, CUtlVector< WeaponProgression > & vecWeaponProgression, const char * szGameType, const char * szGameMode );
GameType *GetGameType_Internal( const char *gameType );
GameMode *GetGameMode_Internal( GameType *pGameType, const char *gameMode );
MapGroup *GetMapGroup_Internal( const char *mapGroup );
GameType *GetCurrentGameType_Internal( void );
GameMode *GetCurrentGameMode_Internal( GameType *pGameType );
Map *GetMap_Internal( const char *mapName );
CustomBotDifficulty *GetCurrentCustomBotDifficulty_Internal( void );
bool GetGameModeAndTypeFromStrings( const char* szGameType, const char* szGameMode, GameType*& outGameType, GameMode*& outGameMode );
private:
CUniformRandomStream m_randomStream;
struct GameType
{
GameType();
~GameType();
int m_Index; // index of the game type in the file
char m_Name[GAMETYPES_MAX_NAME]; // internal name for the game type
char m_NameID[GAMETYPES_MAX_ID]; // UI identifier for the game type name
CUtlVector< GameMode* > m_GameModes; // list of associated game modes
};
struct GameMode
{
GameMode();
~GameMode();
int m_Index; // index of the game mode within the game type
char m_Name[GAMETYPES_MAX_NAME]; // internal name of the game mode
char m_NameID[GAMETYPES_MAX_ID]; // UI identifier for the game mode name
char m_NameID_SP[GAMETYPES_MAX_ID]; // UI identifier for the game mode name
char m_DescID[GAMETYPES_MAX_ID]; // UI identifier game mode description
char m_DescID_SP[GAMETYPES_MAX_ID]; // UI identifier game mode description
int m_MaxPlayers; // maximum number of players for the mode
KeyValues* m_pExecConfings; // configs to exec for this game mode
CUtlStringList m_MapGroupsSP; // single player map groups
CUtlStringList m_MapGroupsMP; // multiplayer map groups
CUtlVector< WeaponProgression > m_WeaponProgressionCT; // CT weapon progression for this game mode (only gun game)
CUtlVector< WeaponProgression > m_WeaponProgressionT; // T weapon progression for this game mode (only gun game)
int m_NoResetVoteThresholdCT;
int m_NoResetVoteThresholdT;
};
struct Map
{
Map();
int m_Index; // index of the map
char m_Name[MAX_MAP_NAME]; // internal name for the map (matches the filename without extension)
char m_NameID[GAMETYPES_MAX_ID]; // UI identifier for the map name
char m_ImageName[GAMETYPES_MAX_IMAGE_NAME]; // texture for map image
uint32 m_RichPresence; // optional rich presence context
CUtlStringList m_TModels; // list of model filenames for Ts
CUtlStringList m_CTModels; // list of model filenames for CTs
CUtlStringList m_HostageModels; // list of model filenames for Hostages
CUtlString m_TViewModelArms; // name of the model used for the terrorists arms.
CUtlString m_CTViewModelArms; // name of the model used for the counter-terrorists arms.
int m_nDefaultGameType;
int m_nDefaultGameMode;
char m_RequiresAttr[MAX_PATH]; // Attribute to check for the map
int m_RequiresAttrValue; // Required value of that attribute for the map
char m_RequiresAttrReward[MAX_PATH]; // Attribute to reward for the map
int m_nRewardDropList; // Weapon case (sometimes?) rewarded while playing in this map
};
struct MapGroup
{
MapGroup();
char m_Name[GAMETYPES_MAX_MAP_GROUP_NAME]; // internal name for the map group
char m_NameID[GAMETYPES_MAX_ID]; // UI identifier for the map name
char m_ImageName[GAMETYPES_MAX_IMAGE_NAME]; // texture for map image
CUtlStringList m_Maps;
bool m_bIsWorkshopMapGroup;
};
struct CustomBotDifficulty
{
CustomBotDifficulty();
~CustomBotDifficulty();
int m_Index; // index of the difficulty level
char m_Name[GAMETYPES_MAX_NAME]; // internal name
char m_NameID[GAMETYPES_MAX_ID]; // UI identifier
KeyValues* m_pConvars; // convars associated with the bot difficulty
bool m_HasBotQuota; // true if this difficulty level has a bot quota in the convars
};
MapGroup *CreateWorkshopMapGroupInternal( const char* szName, const CUtlStringList & vecMapNames );
int FindWeaponProgressionIndex( CUtlVector< WeaponProgression > & vecWeaponProgression, const char * szWeaponName );
void ClearServerMapGroupInfo( void );
bool m_Initialized; // true if the game types interface has been initialized
CUtlVector< GameType* > m_GameTypes; // list of game types
CUtlVector< Map* > m_Maps; // list of maps
CUtlVector< MapGroup* > m_MapGroups; // list of map groups for cycling maps
CUtlVector< CustomBotDifficulty* > m_CustomBotDifficulties; // list of custom bot difficulty levels for Offline Games
bool GetRunMapWithDefaultGametype() { return m_bRunMapWithDefaultGametype; }
void SetRunMapWithDefaultGametype( bool bDefaultGametype ) { m_bRunMapWithDefaultGametype = bDefaultGametype; }
bool GetLoadingScreenDataIsCorrect() { return m_bLoadingScreenDataIsCorrect; }
void SetLoadingScreenDataIsCorrect( bool bLoadingScreenDataIsCorrect ) { m_bLoadingScreenDataIsCorrect = bLoadingScreenDataIsCorrect; }
// These are filled out on the client when connecting to a server
KeyValues *m_pExtendedServerInfo;
Map* m_pServerMap; // map on the currently connected server
MapGroup* m_pServerMapGroup; // map group for cycling maps on the currently connected server
int m_iCurrentServerNumSlots;
// if this is true when the Level init happens, we'll run whatever game type and mode that the map defines in its KV file
// if this is set to false, we know the map was executed via a method that sets the mode and type (like via the menu UI)
bool m_bRunMapWithDefaultGametype;
// unless we load through the main menu, we don't trust the data that the loading screen has
// this keeps track of whehther the data the loading screen has is correct or not
bool m_bLoadingScreenDataIsCorrect;
};
#endif // GAME_TYPES_H
@@ -0,0 +1,163 @@
//========= Copyright © 1996-2005, 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"
#include "decals.h"
#include "bot_manager.h"
#define GRENADE_MODEL "models/Weapons/w_eq_fraggrenade_dropped.mdl"
LINK_ENTITY_TO_CLASS( hegrenade_projectile, CHEGrenadeProjectile );
PRECACHE_REGISTER( hegrenade_projectile );
#if !defined( CLIENT_DLL )
BEGIN_DATADESC( CHEGrenadeProjectile )
// Inputs
DEFINE_INPUTFUNC( FIELD_VOID, "InitializeSpawnFromWorld", InitializeSpawnFromWorld ),
END_DATADESC()
#endif
CHEGrenadeProjectile* CHEGrenadeProjectile::Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
const CCSWeaponInfo& weaponInfo,
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->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 = &weaponInfo;
pGrenade->m_flDamage = (float)weaponInfo.GetDamage(); // 100;
pGrenade->m_DmgRadius = weaponInfo.GetRange(); // pGrenade->m_flDamage * 3.5f;
pGrenade->SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
return pGrenade;
}
void CHEGrenadeProjectile::Spawn()
{
SetModel( GRENADE_MODEL );
BaseClass::Spawn();
SetBodygroupPreset( "thrown" );
}
void CHEGrenadeProjectile::Precache()
{
PrecacheModel( GRENADE_MODEL );
PrecacheScriptSound( "HEGrenade.Bounce" );
BaseClass::Precache();
}
void CHEGrenadeProjectile::BounceSound( void )
{
EmitSound( "HEGrenade.Bounce" );
}
void CHEGrenadeProjectile::Detonate()
{
// tell the bots an HE grenade has exploded (and record the event in the log)
if ( CCSPlayer *player = ToCSPlayer( GetThrower() ) )
{
IGameEvent * event = gameeventmanager->CreateEvent( "hegrenade_detonate" );
if ( event )
{
event->SetInt( "userid", player->GetUserID() );
event->SetInt( "entityid", this->entindex() );
event->SetFloat( "x", GetAbsOrigin().x );
event->SetFloat( "y", GetAbsOrigin().y );
event->SetFloat( "z", GetAbsOrigin().z );
gameeventmanager->FireEvent( event );
}
}
BaseClass::Detonate();
}
const char *CHEGrenadeProjectile::GetParticleSystemName( int pointContents, surfacedata_t *pdata )
{
if ( pointContents & MASK_WATER )
return "explosion_basic_water";
// [msmith] If the grenade goes off near smoke, then we need to make sure that it doesn't
// spawn any of it's own smoke (the explosion_hegrenade_brief effect has no smoke).
// This fixes an exploit that allowed players to "see through" the smokegrenade smoke.
const Vector *detonatePosition = &GetAbsOrigin();
if ( TheBots->IsInsideSmokeCloud( detonatePosition, HEGrenadeRadius ) )
return "explosion_hegrenade_brief";
if ( pdata )
{
switch( pdata->game.material )
{
case CHAR_TEX_DIRT:
case CHAR_TEX_SAND:
case CHAR_TEX_GRASS:
case CHAR_TEX_MUD:
case CHAR_TEX_FOLIAGE:
return "explosion_hegrenade_dirt";
case CHAR_TEX_SNOW:
return "explosion_hegrenade_snow";
}
}
return "explosion_basic";
}
void CHEGrenadeProjectile::InitializeSpawnFromWorld( inputdata_t &inputdata )
{
SetDetonateTimerLength( 1.5 );
SetGravity( GetGrenadeGravity() );
SetFriction( GetGrenadeFriction() );
SetElasticity( GetGrenadeElasticity() );
//pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
ApplyLocalAngularVelocityImpulse( AngularImpulse(600,random->RandomInt(-1200,1200),0) );
// make NPCs afaid of it while in the air
SetThink( &CHEGrenadeProjectile::DangerSoundThink );
SetNextThink( gpGlobals->curtime );
m_pWeaponInfo = GetWeaponInfo( WEAPON_HEGRENADE );
//m_flDamage = (float)m_pWeaponInfo.GetDamage(); // 100;
//m_DmgRadius = m_pWeaponInfo.GetRange(); // pGrenade->m_flDamage * 3.5f;
SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
}
@@ -0,0 +1,57 @@
//========= Copyright © 1996-2005, 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 );
#if !defined( CLIENT_DLL )
DECLARE_DATADESC();
#endif
// Overrides.
public:
CHEGrenadeProjectile() {}
virtual void Spawn();
virtual void Precache();
virtual void BounceSound( void );
virtual void Detonate();
virtual const char *GetParticleSystemName( int pointContents, surfacedata_t *pdata );
virtual GrenadeType_t GetGrenadeType( void ) { return GRENADE_TYPE_EXPLOSIVE; }
// Grenade stuff.
public:
static CHEGrenadeProjectile* Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
const CCSWeaponInfo& weaponInfo,
float timer );
void SetTimer( float timer );
void InitializeSpawnFromWorld( inputdata_t &inputdata );
private:
float m_flDetonateTime;
};
#endif // HEGRENADE_PROJECTILE_H
+48
View File
@@ -0,0 +1,48 @@
//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=====================================================================================//
#include "cbase.h"
#if defined ( GAME_DLL )
#include "Effects/inferno.h"
#define INFERNOCLASS CInferno
#define FIRECRACKERBLASTCLASS CFireCrackerBlast
#endif
#if defined( CLIENT_DLL )
#include "Effects/clientinferno.h"
#define INFERNOCLASS C_Inferno
#define FIRECRACKERBLASTCLASS C_FireCrackerBlast
#endif
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
//---------------------------------------------------------
const char *INFERNOCLASS::GetParticleEffectName()
{
return "molotov_groundfire";
}
#if defined( GAME_DLL )
const char *INFERNOCLASS::GetImpactParticleEffectName()
{
return "molotov_explosion";
}
#endif
//---------------------------------------------------------
const char *FIRECRACKERBLASTCLASS::GetParticleEffectName()
{
return "firework_crate_ground_effect";
}
#if defined( GAME_DLL )
const char *FIRECRACKERBLASTCLASS::GetImpactParticleEffectName()
{
return "firework_crate_explosion_01";
}
#endif
+165
View File
@@ -0,0 +1,165 @@
//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============//
//
// Purpose: Healthshot Item, belt item
//
// $NoKeywords: $
//=====================================================================================//
#include "cbase.h"
#include "item_healthshot.h"
#include "cs_gamerules.h"
#include "econ_entity_creation.h"
#if defined( CLIENT_DLL )
#include "c_cs_player.h"
#else
#include "cs_player.h"
#endif // CLIENT_DLL
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
#define HEALTHSHOT_INJECT_TIME 1.65f
IMPLEMENT_NETWORKCLASS_ALIASED( Item_Healthshot, DT_Item_Healthshot )
BEGIN_NETWORK_TABLE( CItem_Healthshot, DT_Item_Healthshot )
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CItem_Healthshot )
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS_ALIASED( weapon_healthshot, Item_Healthshot );
PRECACHE_WEAPON_REGISTER( weapon_healthshot );
// #ifndef CLIENT_DLL
// BEGIN_DATADESC( CItem_Healthshot )
// END_DATADESC()
// #endif
ConVar healthshot_health( "healthshot_health", "50", FCVAR_CHEAT | FCVAR_REPLICATED );
void CItem_Healthshot::WeaponIdle()
{
if (m_flTimeWeaponIdle > gpGlobals->curtime)
return;
SendWeaponAnim( ACT_VM_IDLE );
SetWeaponIdleTime( gpGlobals->curtime + 20 );
}
void CItem_Healthshot::Precache( void )
{
//PrecacheScriptSound( "Healthshot.Shot" );
BaseClass::Precache();
}
bool CItem_Healthshot::CanPrimaryAttack( void )
{
CCSPlayer *pPlayer = ToCSPlayer( GetPlayerOwner() );
if ( pPlayer == NULL )
return false;
return CanUseOnSelf( pPlayer );
}
bool CItem_Healthshot::CanUseOnSelf( CCSPlayer *pPlayer )
{
if ( !pPlayer )
return false;
if ( pPlayer->GetHealth() >= pPlayer->GetMaxHealth() )
{
#ifndef CLIENT_DLL
ClientPrint( pPlayer, HUD_PRINTCENTER, "#SFUI_Healthshot_AlreadyAtMax" );
#endif
return false;
}
return true;
}
void CItem_Healthshot::DropHealthshot( void )
{
#ifndef CLIENT_DLL
CCSPlayer *pPlayer = ToCSPlayer( GetPlayerOwner() );
if ( !pPlayer )
return;
int iAmount = pPlayer->GetAmmoCount( GetPrimaryAmmoType() );
if ( iAmount <= 1 )
{
pPlayer->CSWeaponDrop( this, false, true );
return;
}
else
{
pPlayer->RemoveAmmo( 1, AMMO_TYPE_HEALTHSHOT );
CItem_Healthshot *pHealth = static_cast< CItem_Healthshot * >( CreateEntityByName( "weapon_healthshot" ) );
if ( pHealth )
{
Vector vecWeaponThrowFromPos = pPlayer->EyePosition();
QAngle angWeaponThrowFromAngle = pPlayer->EyeAngles();
Vector vForward;
AngleVectors(angWeaponThrowFromAngle, &vForward, NULL, NULL);
vecWeaponThrowFromPos = vecWeaponThrowFromPos + (vForward * 100);
//NDebugOverlay::Box( vecWeaponThrowFromPos, Vector( 10, 10, 10 ), Vector( -10, -10, -10 ), 255, 0, 0, 200, 3 );
DispatchSpawn( pHealth );
// set it non-solid because it hits itself during the trace when trying to throw it
pHealth->SetSolidFlags( FSOLID_NOT_SOLID );
pHealth->SetMoveCollide( MOVECOLLIDE_FLY_BOUNCE );
pPlayer->Weapon_Drop( pHealth, &vecWeaponThrowFromPos, NULL );
pHealth->SetSolidFlags( FSOLID_NOT_STANDABLE | FSOLID_TRIGGER | FSOLID_USE_TRIGGER_BOUNDS );
pHealth->SetPreviousOwner( pPlayer );
pHealth->m_flDroppedAtTime = gpGlobals->curtime;
pHealth->AddPriorOwner( pPlayer );
}
}
#endif
}
//--------------------------------------------------------------------------------------------------------
void CItem_Healthshot::OnStartUse( CCSPlayer *pPlayer )
{
SetWeaponIdleTime( gpGlobals->curtime + 20 ); // don't fidget for a bit
BaseClass::OnStartUse( pPlayer );
}
#ifndef CLIENT_DLL
//--------------------------------------------------------------------------------------------------------
void CItem_Healthshot::CompleteUse( CCSPlayer *pPlayer )
{
pPlayer->OnHealthshotUsed();
// Give half health buffer
pPlayer->SetHealth( Min( pPlayer->GetHealth() + healthshot_health.GetInt(), pPlayer->GetMaxHealth() ) );
// emit event
// IGameEvent *event = gameeventmanager->CreateEvent( "healthshot_used" );
// if( event )
// {
// int userID = pPlayer->GetUserID();
// event->SetInt( "userid", userID );
// event->SetInt( "subject", userID );
// gameeventmanager->FireEvent( event );
// }
BaseClass::CompleteUse( pPlayer );
}
#endif //CLIENT_DLL
float CItem_Healthshot::GetUseTimerDuration( void )
{
return HEALTHSHOT_INJECT_TIME;
}
+60
View File
@@ -0,0 +1,60 @@
//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============//
//
// Purpose: Healthshot, it makes you go
//
// $NoKeywords: $
//=====================================================================================//
#ifndef _ITEM_HEALTHSHOT_H_
#define _ITEM_HEALTHSHOT_H_
#ifdef _WIN32
#pragma once
#endif
#include "weapon_baseitem.h"
#include "util_shared.h"
#if defined( CLIENT_DLL )
#define CItem_Healthshot C_Item_Healthshot
#endif
//-----------------------------------------------------------------------------------------------------------
/**
* Healthshot. When used, give the player speed boost for a short amount of time
*/
class CItem_Healthshot : public CWeaponBaseItem
{
public:
DECLARE_CLASS( CItem_Healthshot, CWeaponBaseItem );
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
// #ifndef CLIENT_DLL
// DECLARE_DATADESC();
// #endif
CItem_Healthshot() {}
virtual void Precache( void );
virtual bool CanPrimaryAttack( void );
virtual CSWeaponID GetCSWeaponID( void ) const { return WEAPON_HEALTHSHOT; }
void DropHealthshot( void );
// CBaseBeltItem
virtual bool CanUseOnSelf( CCSPlayer *pPlayer );
virtual void OnStartUse( CCSPlayer *pPlayer );
virtual float GetUseTimerDuration( void );
virtual void WeaponIdle();
#ifndef CLIENT_DLL
virtual void CompleteUse( CCSPlayer *pPlayer );
#endif
private:
CItem_Healthshot( const CItem_Healthshot & ) {}
};
#endif // _ITEM_HEALTHSHOT_H_
+347
View File
@@ -0,0 +1,347 @@
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "item_sonarpulse.h"
#ifdef CLIENT_DLL
#include "view.h"
#include "materialsystem/imaterialvar.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define SONARPULSE_MODEL "models/props/props_br/br_sonar/br_sonar.mdl"
#define SONARPULSE_SPEED 270 // in units/sec
#define SONARPULSE_PRICE 1000 // in american dollars
#ifdef CLIENT_DLL
CUtlVector<CSonarPulse*> g_SonarPulsers;
CUtlVector<sonarpulseicon_t> g_SonarPulseIcons;
#endif
#if defined( CLIENT_DLL )
#else
BEGIN_DATADESC( CSonarPulse )
END_DATADESC()
#endif
BEGIN_PREDICTION_DATA( CSonarPulse )
END_PREDICTION_DATA()
IMPLEMENT_NETWORKCLASS_ALIASED( SonarPulse, DT_SonarPulse )
BEGIN_NETWORK_TABLE( CSonarPulse, DT_SonarPulse )
#ifdef CLIENT_DLL
RecvPropBool( RECVINFO(m_bPulseInProgress) ),
RecvPropFloat( RECVINFO(m_flPulseInitTime) )
#else
SendPropBool( SENDINFO(m_bPulseInProgress) ),
SendPropFloat( SENDINFO(m_flPulseInitTime) )
#endif
END_NETWORK_TABLE()
LINK_ENTITY_TO_CLASS_ALIASED( item_sonarpulse, SonarPulse );
PRECACHE_REGISTER( item_sonarpulse );
CSonarPulse::CSonarPulse()
{
#ifndef CLIENT_DLL
m_bPulseInProgress = false;
m_flPulseInitTime = 0;
m_vecPlayersOutsidePulse.RemoveAll();
m_vecPingedPlayers.RemoveAll();
m_flPlaybackRate = 0;
#else
ListenForGameEvent( "add_player_sonar_icon" );
g_SonarPulsers.FindAndFastRemove( this );
g_SonarPulsers.AddToTail( this );
m_pIconMaterial = NULL;
g_SonarPulseIcons.RemoveAll();
#endif
}
CSonarPulse::~CSonarPulse()
{
#ifdef CLIENT_DLL
g_SonarPulsers.FindAndFastRemove( this );
#endif
}
void CSonarPulse::Spawn( void )
{
BaseClass::Spawn();
SetMoveType( MOVETYPE_NONE );
SetSolid( SOLID_VPHYSICS );
SetModel( SONARPULSE_MODEL );
#ifdef CLIENT_DLL
m_pIconMaterial = materials->FindMaterial( "dev/sonar_icon.vmt", TEXTURE_GROUP_OTHER, false );
SetThink( &CSonarPulse::ClientThink );
SetNextClientThink( CLIENT_THINK_ALWAYS );
#else
SetPlaybackRate( 0 );
#endif
}
void CSonarPulse::Precache()
{
PrecacheModel( SONARPULSE_MODEL );
PrecacheSound( "ambient/atmosphere/cs_metalscrapeverb10.wav" );
}
float CSonarPulse::GetPulseRadius( void )
{
if ( !m_bPulseInProgress )
return 0;
float flCurrentDuration = gpGlobals->curtime - m_flPulseInitTime;
return flCurrentDuration * SONARPULSE_SPEED;
}
Vector CSonarPulse::GetPulseOrigin( void )
{
return GetAbsOrigin();
}
#ifdef CLIENT_DLL
void CSonarPulse::ClientThink( void )
{
StudioFrameAdvance();
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
void CSonarPulse::RenderIcons( void )
{
if( !g_SonarPulseIcons.Count() || m_pIconMaterial == NULL )
return;
C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
if ( !pLocalPlayer )
return;
Vector vecEyePos = MainViewOrigin(GET_ACTIVE_SPLITSCREEN_SLOT());
CMatRenderContextPtr pRenderContext(materials);
FOR_EACH_VEC_BACK( g_SonarPulseIcons, n )
{
float flLifeTimeRemaining = g_SonarPulseIcons[n].GetLifeRemaining();
if ( flLifeTimeRemaining > 0 )
{
Vector vecIconPos = g_SonarPulseIcons[n].m_vecPos;
Vector vecOrigin;
ScreenTransform( vecIconPos, vecOrigin );
float flSize = RemapValClamped( flLifeTimeRemaining, 10, 9, 1, 32 );
float flEdgeAlpha = 1.0f;
float flTheta = 0.95f;
if ( vecOrigin.Length() > flTheta )
{
vecOrigin = vecOrigin.Normalized() * flTheta;
flSize = MIN( flSize, 24 );
flEdgeAlpha = 0.7f;
}
ConvertNormalizedScreenSpaceToPixelScreenSpace( vecOrigin );
//scale size by distance a bit, as per Brian's request.
flSize *= RemapValClamped( vecEyePos.DistToSqr( vecIconPos ), 1600*1600, 500*500, 0.5f, 1.0f );
vecOrigin.x -= flSize * 0.5f;
vecOrigin.y -= flSize * 0.5f;
IMaterialVar* pVar = m_pIconMaterial->FindVar( "$alpha", NULL );
if ( pVar )
{
pVar->SetFloatValue( flEdgeAlpha * clamp( flLifeTimeRemaining * 0.5f, 0, 1 ) );
}
pRenderContext->DrawScreenSpaceRectangle( m_pIconMaterial,
vecOrigin.x, vecOrigin.y,
flSize, flSize,
0, 0, 32, 32, 32, 32 );
}
else
{
g_SonarPulseIcons.FastRemove( n );
}
}
}
void CSonarPulse::FireGameEvent( IGameEvent *event )
{
if ( Q_strcmp( event->GetName(), "add_player_sonar_icon" ) == 0 )
{
// don't make an icon for the local player - it's confusing
int nUserID = event->GetInt( "userid", -1 );
C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
if ( pLocalPlayer && pLocalPlayer->GetUserID() == nUserID )
return;
Vector vecPos = Vector( event->GetFloat("pos_x",0), event->GetFloat("pos_y",0), event->GetFloat("pos_z",0) );
sonarpulseicon_t newIcon( vecPos );
g_SonarPulseIcons.AddToTail( newIcon );
//CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByUserId( nUserID ) );
//ConColorMsg( Color(0,255,255,255), "RECEIVE: sonar icon added at [%f, %f, %f] for player: %s\n", vecPos.x, vecPos.y, vecPos.z, pPlayer ? pPlayer->GetPlayerName() : "null" );
}
}
#endif
#ifndef CLIENT_DLL
void CSonarPulse::PulseStart( void )
{
EmitSound( "ambient/atmosphere/cs_metalscrapeverb10.wav" );
m_vecPlayersOutsidePulse.RemoveAll();
m_vecPingedPlayers.RemoveAll();
m_bPulseInProgress = true;
m_flPulseInitTime = gpGlobals->curtime;
SetPlaybackRate( 1 );
SetThink( &CSonarPulse::PulseThink );
SetNextThink( gpGlobals->curtime );
}
void CSonarPulse::PulseReset( void )
{
SetThink( NULL );
SetPlaybackRate( 0 );
m_bPulseInProgress = false;
m_flPulseInitTime = 0;
m_vecPlayersOutsidePulse.RemoveAll();
m_vecPingedPlayers.RemoveAll();
m_flPlaybackRate = 0;
}
bool CSonarPulse::IsOkToPulse( CCSPlayer* pPlayer )
{
return ( pPlayer && pPlayer->IsAlive() && !pPlayer->IsChickenClass() && !pPlayer->IsFlyingDroneClass() && !pPlayer->m_bIsParachuting );
}
void CSonarPulse::PulseThink( void )
{
if ( !m_bPulseInProgress )
{
PulseReset();
return;
}
float flRadius = GetPulseRadius();
Vector vecPulseCenter = GetPulseOrigin();
float flRadSqrCurrent = flRadius * flRadius;
// ping the players that were outside the pulse last think and are now inside
FOR_EACH_VEC_BACK( m_vecPlayersOutsidePulse, n )
{
CCSPlayer *pPlayer = ToCSPlayer( m_vecPlayersOutsidePulse[n] );
if ( IsOkToPulse( pPlayer ) )
{
Vector vecPlayerPos = pPlayer->GetAbsOrigin() + Vector(0,0,40);
float flPlayerDist = vecPlayerPos.DistToSqr( vecPulseCenter );
if ( flPlayerDist < flRadSqrCurrent && !m_vecPingedPlayers.HasElement( pPlayer ) )
{
// The pulse crossed this player - ping them!
pPlayer->EmitSound( "Bot.StuckSound" );
IGameEvent * sonar_ping_event = gameeventmanager->CreateEvent( "add_player_sonar_icon" );
if ( sonar_ping_event )
{
sonar_ping_event->SetInt( "userid", pPlayer->GetUserID() );
sonar_ping_event->SetFloat( "pos_x", vecPlayerPos.x );
sonar_ping_event->SetFloat( "pos_y", vecPlayerPos.y );
sonar_ping_event->SetFloat( "pos_z", vecPlayerPos.z );
gameeventmanager->FireEvent( sonar_ping_event );
}
m_vecPlayersOutsidePulse.FindAndRemove( pPlayer );
m_vecPingedPlayers.AddToTail( pPlayer );
//ConColorMsg( Color(0,255,0,255), "SEND: sonar icon added at [%f, %f, %f] for player: %s\n", vecPlayerPos.x, vecPlayerPos.y, vecPlayerPos.z, pPlayer->GetPlayerName() );
}
}
else
{
// player is invalid for some reason, might have left, been killed, etc
m_vecPlayersOutsidePulse.FindAndRemove( pPlayer );
}
}
// re-gather players to add to the list that are outside the pulse
for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
if ( IsOkToPulse( pPlayer ) )
{
Vector vecPlayerPos = pPlayer->GetAbsOrigin() + Vector(0,0,40);
float flPlayerDist = vecPlayerPos.DistToSqr( vecPulseCenter );
if ( flPlayerDist > flRadSqrCurrent && !m_vecPlayersOutsidePulse.HasElement(pPlayer) )
{
m_vecPlayersOutsidePulse.AddToTail( pPlayer );
}
}
}
if ( m_vecPlayersOutsidePulse.Count() == 0 )
{
PulseReset();
return;
}
SetNextThink( gpGlobals->curtime + 0.1f );
}
void CSonarPulse::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
CCSPlayer *pPlayer = dynamic_cast< CCSPlayer* >( pActivator );
if ( !pPlayer )
return;
int nCost = SONARPULSE_PRICE;
if ( m_bPulseInProgress || pPlayer->GetAccountBalance() < nCost )
{
// we dont have enough money
// play an error sound
Vector soundPosition = GetAbsOrigin() + Vector( 0, 0, 32 );
CPASAttenuationFilter filter( soundPosition );
EmitSound( filter, 0, "Vote.Failed", &GetAbsOrigin() );
return;
}
// deduct the amount
pPlayer->AddAccount( -nCost, false, true, "" );
m_bPulseInProgress = true;
SetThink( &CSonarPulse::PulseStart );
SetNextThink( gpGlobals->curtime + 1 );
EmitSound( "UI.Guardian.TooFarWarning" );
}
#endif // #ifndef CLIENT_DLL
+117
View File
@@ -0,0 +1,117 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef ITEM_SONARPULSE_H
#define ITEM_SONARPULSE_H
#ifdef _WIN32
#pragma once
#endif
#include "cbase.h"
#include "utlvector.h"
#if defined( CLIENT_DLL )
#include "c_cs_player.h"
#include "c_baseanimating.h"
#include "GameEventListener.h"
#define CSonarPulse C_SonarPulse
#else
#include "cs_player.h"
#include "baseanimating.h"
#endif
#ifdef CLIENT_DLL
#define SONARPULSE_ICON_LIFETIME 10.0f
struct sonarpulseicon_t
{
Vector m_vecPos;
float m_flTimeCreated;
sonarpulseicon_t( Vector vecPos )
{
m_vecPos = vecPos;
m_flTimeCreated = gpGlobals->curtime;
}
float GetLifeRemaining( void )
{
return SONARPULSE_ICON_LIFETIME - (gpGlobals->curtime - m_flTimeCreated);
}
};
#endif
class CSonarPulse : public CBaseAnimating
#ifdef CLIENT_DLL
, public CGameEventListener
#endif
{
public:
DECLARE_CLASS( CSonarPulse, CBaseAnimating );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
#if !defined( CLIENT_DLL )
DECLARE_DATADESC();
#endif
CSonarPulse();
virtual ~CSonarPulse();
virtual void Spawn();
virtual void Precache();
float GetPulseRadius( void );
Vector GetPulseOrigin( void );
#if defined( CLIENT_DLL )
void FireGameEvent( IGameEvent *event );
void RenderIcons( void );
IMaterial *m_pIconMaterial;
void ClientThink( void );
#else
// need to always transmit since we want to see the pulse edge even when the center is way out of pvs
virtual int UpdateTransmitState() { return SetTransmitState( FL_EDICT_ALWAYS ); }
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo ){ return FL_EDICT_ALWAYS; }
virtual int ObjectCaps() { return BaseClass::ObjectCaps() | (FCAP_ONOFF_USE); }
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void PulseStart( void );
void PulseThink( void );
void PulseReset( void );
bool IsOkToPulse( CCSPlayer* pPlayer );
CUtlVector<CCSPlayer*>m_vecPlayersOutsidePulse;
CUtlVector<CCSPlayer*>m_vecPingedPlayers;
#endif
CNetworkVar( bool, m_bPulseInProgress );
CNetworkVar( float, m_flPulseInitTime );
CNetworkVar( float, m_flPlaybackRate );
};
#endif // ITEM_CRATEBEACON_H
@@ -0,0 +1,419 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "molotov_projectile.h"
#include "keyvalues.h"
#include "weapon_csbase.h"
#include "particle_parse.h"
#if defined( CLIENT_DLL )
#include "particle_parse.h"
#include "c_cs_player.h"
#else
#include "cs_player.h"
#include "smoke_trail.h"
#include "Effects/inferno.h"
#include "bot_manager.h"
#endif
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
ConVar molotov_throw_detonate_time( "molotov_throw_detonate_time", "2.0", FCVAR_CHEAT | FCVAR_REPLICATED );
#if defined( CLIENT_DLL )
IMPLEMENT_CLIENTCLASS_DT( C_MolotovProjectile, DT_MolotovProjectile, CMolotovProjectile )
RecvPropBool( RECVINFO(m_bIsIncGrenade) ),
END_RECV_TABLE()
//--------------------------------------------------------------------------------------------------------
void C_MolotovProjectile::OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect )
{
if ( FStrEq( pszParticleName, "weapon_molotov_thrown" ) || FStrEq( pszParticleName, "incgrenade_thrown_trail" ) )
{
m_molotovParticleEffect = pNewParticleEffect;
}
}
//--------------------------------------------------------------------------------------------------------
void C_MolotovProjectile::OnParticleEffectDeleted( CNewParticleEffect *pParticleEffect )
{
if ( m_molotovParticleEffect == pParticleEffect )
{
m_molotovParticleEffect = NULL;
}
}
//--------------------------------------------------------------------------------------------------------
bool C_MolotovProjectile::Simulate( void )
{
if ( !m_molotovParticleEffect.IsValid() )
{
if ( m_bIsIncGrenade )
// todo: make this come from an attachment
DispatchParticleEffect( "incgrenade_thrown_trail", PATTACH_POINT_FOLLOW, this, "trail" );
else
DispatchParticleEffect( "weapon_molotov_thrown", PATTACH_POINT_FOLLOW, this, "Wick" );
}
else
{
m_molotovParticleEffect->SetSortOrigin( GetAbsOrigin() );
m_molotovParticleEffect->SetNeedsBBoxUpdate( true );
}
BaseClass::Simulate();
return true;
}
#else // GAME_DLL
ConVar weapon_molotov_maxdetonateslope(
"weapon_molotov_maxdetonateslope",
"30.0",
FCVAR_REPLICATED,
"Maximum angle of slope on which the molotov will detonate",
true, 0.0,
true, 90.0 );
#define MOLOTOV_MODEL "models/Weapons/w_eq_molotov_dropped.mdl"
#define INCGREN_MODEL "models/Weapons/w_eq_incendiarygrenade_dropped.mdl"
LINK_ENTITY_TO_CLASS( molotov_projectile, CMolotovProjectile );
PRECACHE_REGISTER( molotov_projectile );
BEGIN_DATADESC( CMolotovProjectile )
// Inputs
DEFINE_INPUTFUNC( FIELD_VOID, "InitializeSpawnFromWorld", InitializeSpawnFromWorld ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST( CMolotovProjectile, DT_MolotovProjectile )
SendPropBool( SENDINFO(m_bIsIncGrenade) ),
END_SEND_TABLE()
CMolotovProjectile *CMolotovProjectile::Create( const Vector &position, const QAngle &angles,
const Vector &velocity, const AngularImpulse &angVelocity,
CBaseCombatCharacter *owner, const CCSWeaponInfo& weaponInfo )
{
CMolotovProjectile *molotov = (CMolotovProjectile *)CBaseEntity::Create( "molotov_projectile", position, angles, owner );
UTIL_LogPrintf( "Molotov projectile spawned at %f %f %f, velocity %f %f %f\n", position.x, position.y, position.z, velocity.x, velocity.y, velocity.z );
molotov->SetDetonateTimerLength( molotov_throw_detonate_time.GetFloat() );
molotov->SetAbsVelocity( velocity );
molotov->SetupInitialTransmittedGrenadeVelocity( velocity );
molotov->SetThrower( owner );
molotov->m_pWeaponInfo = &weaponInfo;
molotov->SetIsIncGrenade( weaponInfo.m_weaponId == WEAPON_INCGRENADE );
if ( molotov->m_bIsIncGrenade )
molotov->SetModel( INCGREN_MODEL );
else
molotov->SetModel( MOLOTOV_MODEL );
molotov->SetGravity( BaseClass::GetGrenadeGravity() );
molotov->SetFriction( BaseClass::GetGrenadeFriction() );
molotov->SetElasticity( BaseClass::GetGrenadeElasticity() );
molotov->SetTouch( &CMolotovProjectile::BounceTouch );
molotov->SetThink( &CMolotovProjectile::DetonateThink );
molotov->SetNextThink( gpGlobals->curtime + 2.0f );
molotov->m_flDamage = 200.0f;
molotov->m_DmgRadius = 300.0f;
molotov->ChangeTeam( owner->GetTeamNumber() );
molotov->ApplyLocalAngularVelocityImpulse( angVelocity );
// make NPCs afaid of it while in the air
molotov->SetThink( &CMolotovProjectile::DangerSoundThink );
molotov->SetNextThink( gpGlobals->curtime );
molotov->EmitSound( "Molotov.Throw" );
molotov->EmitSound( "Molotov.Loop" );
molotov->SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
// we have to reset these here because we set the model late and it resets the collision
Vector min = Vector( -GRENADE_DEFAULT_SIZE, -GRENADE_DEFAULT_SIZE, -GRENADE_DEFAULT_SIZE );
Vector max = Vector( GRENADE_DEFAULT_SIZE, GRENADE_DEFAULT_SIZE, GRENADE_DEFAULT_SIZE );
molotov->SetSize( min, max );
if ( molotov->CollisionProp() )
molotov->CollisionProp()->SetCollisionBounds( min, max );
return molotov;
}
void CMolotovProjectile::InitializeSpawnFromWorld( inputdata_t &inputdata )
{
SetDetonateTimerLength( molotov_throw_detonate_time.GetFloat() );
SetGravity( GetGrenadeGravity() );
SetFriction( GetGrenadeFriction() );
SetElasticity( GetGrenadeElasticity() );
SetIsIncGrenade( false );
SetTouch( &CMolotovProjectile::BounceTouch );
SetThink( &CMolotovProjectile::DetonateThink );
SetNextThink( gpGlobals->curtime + 2.0f );
//pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
ApplyLocalAngularVelocityImpulse( AngularImpulse( 600, random->RandomInt( -1200, 1200 ), 0 ) );
// make NPCs afaid of it while in the air
SetThink( &CMolotovProjectile::DangerSoundThink );
SetNextThink( gpGlobals->curtime );
EmitSound( "Molotov.Throw" );
EmitSound( "Molotov.Loop" );
SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
// we have to reset these here because we set the model late and it resets the collision
Vector min = Vector( -GRENADE_DEFAULT_SIZE, -GRENADE_DEFAULT_SIZE, -GRENADE_DEFAULT_SIZE );
Vector max = Vector( GRENADE_DEFAULT_SIZE, GRENADE_DEFAULT_SIZE, GRENADE_DEFAULT_SIZE );
SetSize( min, max );
if ( CollisionProp() )
CollisionProp()->SetCollisionBounds( min, max );
m_pWeaponInfo = GetWeaponInfo( WEAPON_MOLOTOV );
}
void CMolotovProjectile::Spawn( void )
{
m_stillTimer.Invalidate();
m_throwDetTimer.Invalidate();
BaseClass::Spawn();
if ( this->m_bIsIncGrenade )
{
SetModel( INCGREN_MODEL );
SetBodygroupPreset( "thrown" );
}
else
{
SetModel( MOLOTOV_MODEL );
}
}
void CMolotovProjectile::Precache( void )
{
PrecacheModel( MOLOTOV_MODEL );
PrecacheModel( INCGREN_MODEL );
PrecacheScriptSound( "Molotov.Throw" );
PrecacheScriptSound( "Molotov.Loop" );
PrecacheParticleSystem( "weapon_molotov_thrown" );
PrecacheParticleSystem( "weapon_molotov_held" );
PrecacheParticleSystem( "incgrenade_thrown_trail" );
BaseClass::Precache();
}
void CMolotovProjectile::BounceTouch( CBaseEntity *other )
{
if ( other->IsSolidFlagSet( FSOLID_TRIGGER | FSOLID_VOLUME_CONTENTS ) )
return;
// don't hit the guy that launched this grenade
if ( other == GetThrower() )
return;
if ( FClassnameIs( other, "func_breakable" ) )
{
return;
}
if ( FClassnameIs( other, "func_breakable_surf" ) )
{
return;
}
// don't detonate on ladders
if ( FClassnameIs( other, "func_ladder" ) )
{
return;
}
// Deal car alarms direct damage to set them off - flames won't do so
if ( FClassnameIs( other, "prop_car_alarm" ) || FClassnameIs( other, "prop_car_glass" ) )
{
CTakeDamageInfo info( this, GetThrower(), 10, DMG_GENERIC );
other->OnTakeDamage( info );
}
const trace_t &hitTrace = GetTouchTrace();
if ( hitTrace.m_pEnt && hitTrace.m_pEnt->MyCombatCharacterPointer() )
{
// don't break if we hit an actor - wait until we hit the environment
return;
}
else
{
// only detonate on surfaces less steep than this
const float kMinCos = cosf(DEG2RAD(weapon_molotov_maxdetonateslope.GetFloat()));
if ( hitTrace.plane.normal.z >= kMinCos )
{
Detonate();
}
}
}
void CMolotovProjectile::BounceSound( void )
{
if ( m_bIsIncGrenade )
EmitSound( "IncGrenade.Bounce" );
else
EmitSound( "GlassBottle.ImpactHard" );
}
void CMolotovProjectile::DetonateThink( void )
{
// if( gpGlobals->curtime > m_flDetonateTime )
// {
// Detonate();
// return;
// }
if ( GetAbsVelocity().IsLengthGreaterThan( 5.0f ) )
{
m_stillTimer.Invalidate();
}
else if ( !m_stillTimer.HasStarted() )
{
m_stillTimer.Start();
}
const float StillDetonateTime = 0.5f;
if ( m_stillTimer.HasStarted() && m_stillTimer.GetElapsedTime() > StillDetonateTime )
{
Detonate();
}
else
{
SetNextThink( gpGlobals->curtime + 0.1f );
}
TheBots->SetGrenadeRadius( this, 0.0f );
}
void CMolotovProjectile::Detonate( void )
{
//BaseClass::Detonate();
const trace_t &hitTrace = GetTouchTrace();
if ( hitTrace.surface.flags & SURF_SKY )
return;
// tell the bots an HE grenade has exploded
CCSPlayer *player = ToCSPlayer(GetThrower());
if ( player )
{
IGameEvent * event = gameeventmanager->CreateEvent( "molotov_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 );
}
}
Vector burnPos, splashNormal;
if ( hitTrace.DidHitWorld() )
{
// hit the world, just explode at that position
burnPos = hitTrace.endpos;
splashNormal = hitTrace.plane.normal;
}
else
{
// exploded in the air, or hit an object or player.
// find the world normal under them (if close enough) and explode there
trace_t tr;
UTIL_TraceLine( GetAbsOrigin() + Vector( 0, 0, 10 ), GetAbsOrigin() + Vector( 0, 0, -128.0f ), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
if ( tr.fraction == 1 )
{
// Too high, just play explosion effect and don't start a fire
if ( m_bIsIncGrenade )
EmitSound( "Inferno.Start_IncGrenade" );
else
EmitSound( "Inferno.Start" );
TheBots->SetGrenadeRadius( this, MolotovGrenadeRadius );
StopSound( "Molotov.Loop" );
DispatchParticleEffect( "explosion_molotov_air", GetAbsOrigin(), QAngle( 0, 0, 0 ) );
Vector vecAbsOrigin = GetAbsOrigin();
CPASFilter filter( vecAbsOrigin );
te->Explosion( filter, -1.0, // don't apply cl_interp delay
vecAbsOrigin,
0,
32,
25,
TE_EXPLFLAG_NOSOUND | TE_EXPLFLAG_NOFIREBALL | TE_EXPLFLAG_NOPARTICLES,
152,
50 );
UTIL_Remove( this );
return;
}
else if( tr.surface.flags & SURF_SKY )
{
// just bounce
return;
}
// otherwise explode normally
burnPos = tr.endpos;
splashNormal = tr.plane.normal;
}
TheBots->SetGrenadeRadius( this, MolotovGrenadeRadius );
CInferno *inferno = (CInferno *)CBaseEntity::Create( "inferno", burnPos, QAngle( 0, 0, 0 ), GetThrower() );
Vector vBurnDir = m_vInitialVelocity;
vBurnDir.NormalizeInPlace();
vBurnDir *= GetAbsVelocity().Length();
inferno->SetSourceWeaponInfo( m_pWeaponInfo );
if ( m_bIsIncGrenade )
inferno->SetInfernoType( INFERNO_TYPE_INCGREN_FIRE );
else
inferno->SetInfernoType( INFERNO_TYPE_FIRE );
inferno->StartBurning( burnPos, splashNormal, vBurnDir );
if ( inferno->WasCreatedInSmoke() )
{
// we extinguished ourselves with this throw.
m_unOGSExtraFlags |= GRENADE_EXTINGUISHED_INFERNO;
}
// We override the base class detonate and don't chain down--
RecordDetonation();
StopSound( "Molotov.Loop" );
UTIL_Remove( this );
}
#endif
@@ -0,0 +1,88 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#if !defined( MOLOTOV_PROJECTILE_H )
#define MOLOTOV_PROJECTILE_H
#if defined( _WIN32 )
#pragma once
#endif
#include "basecsgrenade_projectile.h"
#if defined( CLIENT_DLL )
class C_MolotovProjectile : public C_BaseCSGrenadeProjectile
{
public:
DECLARE_CLASS( C_MolotovProjectile, C_BaseCSGrenadeProjectile );
DECLARE_NETWORKCLASS();
virtual bool Simulate( void );
virtual void OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect );
virtual void OnParticleEffectDeleted( CNewParticleEffect *pParticleEffect );
protected:
CNetworkVar( bool, m_bIsIncGrenade );
private:
CUtlReference<CNewParticleEffect> m_molotovParticleEffect;
};
#else // GAME_DLL
class CMolotovProjectile : public CBaseCSGrenadeProjectile
{
public:
DECLARE_CLASS( CMolotovProjectile, CBaseCSGrenadeProjectile );
DECLARE_NETWORKCLASS();
DECLARE_DATADESC();
// Overrides.
public:
virtual void Spawn( void );
virtual void Precache( void );
virtual void BounceTouch( CBaseEntity *other );
virtual void BounceSound( void );
virtual void Detonate( void );
// virtual int GetDamageType( void ) const { return DMG_BURN; }
virtual GrenadeType_t GetGrenadeType( void ) { return GRENADE_TYPE_FIRE; }
void SetIsIncGrenade( bool bIsIncGrenade ) { m_bIsIncGrenade = bIsIncGrenade; }
// Grenade stuff.
public:
static CMolotovProjectile* Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
const CCSWeaponInfo& weaponInfo );
void InitializeSpawnFromWorld( inputdata_t &inputdata );
protected:
CNetworkVar( bool, m_bIsIncGrenade );
private:
void DetonateThink( void );
void SetTimer( float timer );
IntervalTimer m_stillTimer;
IntervalTimer m_throwDetTimer;
float m_flDetonateTime;
};
#endif // GAME_DLL
#endif // MOLOTOV_PROJECTILE_H
+181
View File
@@ -0,0 +1,181 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "player_pickup.h"
#include "igameevents.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// player pickup utility routine
void Pickup_ForcePlayerToDropThisObject( CBaseEntity *pTarget )
{
Warning ( "Failing to force player to drop object.\n" );
AssertMsg( 0, "This function is assumed to not be needed in portal 2, if this assert fires we need to fix it." );
#if 0
if ( pTarget == NULL )
return;
IPhysicsObject *pPhysics = pTarget->VPhysicsGetObject();
if ( pPhysics == NULL )
return;
if ( pPhysics->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
{
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
pPlayer->ForceDropOfCarriedPhysObjects( pTarget );
}
#endif
}
void Pickup_OnPhysGunDrop( CBaseEntity *pDroppedObject, CBasePlayer *pPlayer, PhysGunDrop_t Reason )
{
IPlayerPickupVPhysics *pPickup = dynamic_cast<IPlayerPickupVPhysics *>(pDroppedObject);
if ( pPickup )
{
pPickup->OnPhysGunDrop( pPlayer, Reason );
}
}
void Pickup_OnPhysGunPickup( CBaseEntity *pPickedUpObject, CBasePlayer *pPlayer, PhysGunPickup_t reason )
{
IPlayerPickupVPhysics *pPickup = dynamic_cast<IPlayerPickupVPhysics *>(pPickedUpObject);
if ( pPickup )
{
pPickup->OnPhysGunPickup( pPlayer, reason );
}
// send phys gun pickup item event, but only in single player
if ( !g_pGameRules->IsMultiplayer() )
{
IGameEvent *event = gameeventmanager->CreateEvent( "physgun_pickup" );
if ( event )
{
event->SetInt( "entindex", pPickedUpObject->entindex() );
gameeventmanager->FireEvent( event );
}
}
}
bool Pickup_OnAttemptPhysGunPickup( CBaseEntity *pPickedUpObject, CBasePlayer *pPlayer, PhysGunPickup_t reason )
{
IPlayerPickupVPhysics *pPickup = dynamic_cast<IPlayerPickupVPhysics *>(pPickedUpObject);
if ( pPickup )
{
return pPickup->OnAttemptPhysGunPickup( pPlayer, reason );
}
return true;
}
CBaseEntity *Pickup_OnFailedPhysGunPickup( CBaseEntity *pPickedUpObject, Vector vPhysgunPos )
{
IPlayerPickupVPhysics *pPickup = dynamic_cast<IPlayerPickupVPhysics *>(pPickedUpObject);
if ( pPickup )
{
return pPickup->OnFailedPhysGunPickup( vPhysgunPos );
}
return NULL;
}
bool Pickup_GetPreferredCarryAngles( CBaseEntity *pObject, CBasePlayer *pPlayer, matrix3x4_t &localToWorld, QAngle &outputAnglesWorldSpace )
{
IPlayerPickupVPhysics *pPickup = dynamic_cast<IPlayerPickupVPhysics *>(pObject);
if ( pPickup )
{
if ( pPickup->HasPreferredCarryAnglesForPlayer( pPlayer ) )
{
outputAnglesWorldSpace = TransformAnglesToWorldSpace( pPickup->PreferredCarryAngles(), localToWorld );
return true;
}
}
return false;
}
bool Pickup_ForcePhysGunOpen( CBaseEntity *pObject, CBasePlayer *pPlayer )
{
IPlayerPickupVPhysics *pPickup = dynamic_cast<IPlayerPickupVPhysics *>(pObject);
if ( pPickup )
{
return pPickup->ForcePhysgunOpen( pPlayer );
}
return false;
}
AngularImpulse Pickup_PhysGunLaunchAngularImpulse( CBaseEntity *pObject, PhysGunForce_t reason )
{
IPlayerPickupVPhysics *pPickup = dynamic_cast<IPlayerPickupVPhysics *>(pObject);
if ( pPickup != NULL && pPickup->ShouldPuntUseLaunchForces( reason ) )
{
return pPickup->PhysGunLaunchAngularImpulse();
}
return RandomAngularImpulse( -600, 600 );
}
Vector Pickup_DefaultPhysGunLaunchVelocity( const Vector &vecForward, float flMass )
{
#ifdef HL2_DLL
// Calculate the velocity based on physcannon rules
float flForceMax = physcannon_maxforce.GetFloat();
float flForce = flForceMax;
float mass = flMass;
if ( mass > 100 )
{
mass = MIN( mass, 1000 );
float flForceMin = physcannon_minforce.GetFloat();
flForce = SimpleSplineRemapValClamped( mass, 100, 600, flForceMax, flForceMin );
}
return ( vecForward * flForce );
#endif
// Do the simple calculation
return ( vecForward * flMass );
}
Vector Pickup_PhysGunLaunchVelocity( CBaseEntity *pObject, const Vector &vecForward, PhysGunForce_t reason )
{
// The object must be valid
if ( pObject == NULL )
{
Assert( 0 );
return vec3_origin;
}
// Shouldn't ever get here with a non-vphysics object.
IPhysicsObject *pPhysicsObject = pObject->VPhysicsGetObject();
if ( pPhysicsObject == NULL )
{
Assert( 0 );
return vec3_origin;
}
// Call the pickup entity's callback
IPlayerPickupVPhysics *pPickup = dynamic_cast<IPlayerPickupVPhysics *>(pObject);
if ( pPickup != NULL && pPickup->ShouldPuntUseLaunchForces( reason ) )
return pPickup->PhysGunLaunchVelocity( vecForward, pPhysicsObject->GetMass() );
// Do our default behavior
return Pickup_DefaultPhysGunLaunchVelocity( vecForward, pPhysicsObject->GetMass() );
}
bool Pickup_ShouldPuntUseLaunchForces( CBaseEntity *pObject, PhysGunForce_t reason )
{
IPlayerPickupVPhysics *pPickup = dynamic_cast<IPlayerPickupVPhysics *>(pObject);
if ( pPickup )
{
return pPickup->ShouldPuntUseLaunchForces( reason );
}
return false;
}
+87
View File
@@ -0,0 +1,87 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: APIs for player pickup of physics objects
//
//=============================================================================//
#ifndef PLAYER_PICKUP_H
#define PLAYER_PICKUP_H
#ifdef _WIN32
#pragma once
#endif
// Reasons behind a pickup
enum PhysGunPickup_t
{
PICKED_UP_BY_CANNON,
PUNTED_BY_CANNON,
PICKED_UP_BY_PLAYER, // Picked up by +USE, not physgun.
};
// Reasons behind a drop
enum PhysGunDrop_t
{
DROPPED_BY_PLAYER,
THROWN_BY_PLAYER,
DROPPED_BY_CANNON,
LAUNCHED_BY_CANNON,
};
enum PhysGunForce_t
{
PHYSGUN_FORCE_DROPPED, // Dropped by +USE
PHYSGUN_FORCE_THROWN, // Thrown from +USE
PHYSGUN_FORCE_PUNTED, // Punted by cannon
PHYSGUN_FORCE_LAUNCHED, // Launched by cannon
};
void PlayerPickupObject( CBasePlayer *pPlayer, CBaseEntity *pObject );
void Pickup_ForcePlayerToDropThisObject( CBaseEntity *pTarget );
void Pickup_OnPhysGunDrop( CBaseEntity *pDroppedObject, CBasePlayer *pPlayer, PhysGunDrop_t reason );
void Pickup_OnPhysGunPickup( CBaseEntity *pPickedUpObject, CBasePlayer *pPlayer, PhysGunPickup_t reason = PICKED_UP_BY_CANNON );
bool Pickup_OnAttemptPhysGunPickup( CBaseEntity *pPickedUpObject, CBasePlayer *pPlayer, PhysGunPickup_t reason = PICKED_UP_BY_CANNON );
bool Pickup_GetPreferredCarryAngles( CBaseEntity *pObject, CBasePlayer *pPlayer, matrix3x4_t &localToWorld, QAngle &outputAnglesWorldSpace );
bool Pickup_ForcePhysGunOpen( CBaseEntity *pObject, CBasePlayer *pPlayer );
bool Pickup_ShouldPuntUseLaunchForces( CBaseEntity *pObject, PhysGunForce_t reason );
AngularImpulse Pickup_PhysGunLaunchAngularImpulse( CBaseEntity *pObject, PhysGunForce_t reason );
Vector Pickup_DefaultPhysGunLaunchVelocity( const Vector &vecForward, float flMass );
Vector Pickup_PhysGunLaunchVelocity( CBaseEntity *pObject, const Vector &vecForward, PhysGunForce_t reason );
CBaseEntity *Pickup_OnFailedPhysGunPickup( CBaseEntity *pPickedUpObject, Vector vPhysgunPos );
abstract_class IPlayerPickupVPhysics
{
public:
// Callbacks for the physgun/cannon picking up an entity
virtual bool OnAttemptPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason = PICKED_UP_BY_CANNON ) = 0;
virtual CBaseEntity *OnFailedPhysGunPickup( Vector vPhysgunPos ) = 0;
virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason = PICKED_UP_BY_CANNON ) = 0;
virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason ) = 0;
virtual bool HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer = NULL ) = 0;
virtual QAngle PreferredCarryAngles( void ) = 0;
virtual bool ForcePhysgunOpen( CBasePlayer *pPlayer ) = 0;
virtual AngularImpulse PhysGunLaunchAngularImpulse() = 0;
virtual bool ShouldPuntUseLaunchForces( PhysGunForce_t reason ) = 0;
virtual Vector PhysGunLaunchVelocity( const Vector &vecForward, float flMass ) = 0;
};
class CDefaultPlayerPickupVPhysics : public IPlayerPickupVPhysics
{
public:
virtual bool OnAttemptPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason = PICKED_UP_BY_CANNON ) { return true; }
virtual CBaseEntity *OnFailedPhysGunPickup( Vector vPhysgunPos ) { return NULL; }
virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason = PICKED_UP_BY_CANNON ) {}
virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t reason ) {}
virtual bool HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer ) { return false; }
virtual QAngle PreferredCarryAngles( void ) { return vec3_angle; }
virtual bool ForcePhysgunOpen( CBasePlayer *pPlayer ) { return false; }
virtual AngularImpulse PhysGunLaunchAngularImpulse() { return RandomAngularImpulse( -600, 600 ); }
virtual bool ShouldPuntUseLaunchForces( PhysGunForce_t reason ) { return false; }
virtual Vector PhysGunLaunchVelocity( const Vector &vecForward, float flMass )
{
return Pickup_DefaultPhysGunLaunchVelocity( vecForward, flMass );
}
};
#endif // PLAYER_PICKUP_H
@@ -0,0 +1,78 @@
//========= Copyright © Valve Corporation, All rights reserved. ============//
//
// Purpose: Player decals signature validation code
//
//=============================================================================//
#ifndef PLAYERDECALS_SIGNATURE_H
#define PLAYERDECALS_SIGNATURE_H
#ifdef _WIN32
#pragma once
#endif
//
// We will be using RSA 1024-bit private signing key
// PKCS1 signature length is guaranteed to be 128 bytes
//
#define PLAYERDECALS_SIGNATURE_VERSION 1
#define PLAYERDECALS_SIGNATURE_BYTELEN 128
#define PLAYERDECALS_NUMCHARGES 50
#define PLAYERDECALS_UNITS_SIZE 48
#define PLAYERDECALS_COOLDOWN_SECONDS 45
#define PLAYERDECALS_DURATION_SOLID 240
#define PLAYERDECALS_DURATION_FADE1 40
#define PLAYERDECALS_DURATION_FADE2 120
#define PLAYERDECALS_DURATION_APPLY 1.5f
#define PLAYERDECALS_LIMIT_COUNT 100
//
// SECURITY INFORMATION: this file is included in DLLs that are
// shipping to clients and to community gameservers with the intent
// for those processes to verify signatures.
// NEVER include/reference private key data in this header!
// Private key must be used only on GC.
//
inline bool BClientPlayerDecalSignatureComposeSignBuffer( PlayerDecalDigitalSignature const &data, CUtlBuffer &buf )
{
if ( data.endpos_size() != 3 ) return false;
for ( int k = 0; k < 3; ++ k ) buf.PutFloat( data.endpos( k ) );
if ( data.startpos_size() != 3 ) return false;
for ( int k = 0; k < 3; ++k ) buf.PutFloat( data.startpos( k ) );
if ( data.right_size() != 3 ) return false;
for ( int k = 0; k < 3; ++k ) buf.PutFloat( data.right( k ) );
if ( data.normal_size() != 3 ) return false;
for ( int k = 0; k < 3; ++k ) buf.PutFloat( data.normal( k ) );
buf.PutInt( data.tx_defidx() );
buf.PutInt( data.tint_id() );
buf.PutInt( data.entindex() );
buf.PutInt( data.hitbox() );
buf.PutFloat( data.creationtime() );
buf.PutUnsignedInt( data.accountid() );
buf.PutUnsignedInt( data.rtime() );
buf.PutUnsignedInt( data.trace_id() );
return true;
}
inline bool BValidateClientPlayerDecalSignature( PlayerDecalDigitalSignature const &data )
{
CUtlBuffer bufData;
bufData.EnsureCapacity( PLAYERDECALS_SIGNATURE_BYTELEN );
if ( !BClientPlayerDecalSignatureComposeSignBuffer( data, bufData ) )
return false;
// Removed for partner depot
return true;
}
#endif // PLAYERDECALS_SIGNATURE_H
+147
View File
@@ -0,0 +1,147 @@
START_SCHEMA( GC, cbase.h )
// --------------------------------------------------------
// WARNING! All new tables need to be added to the end of the file
// if you expect to deploy the GC without deploying new clients.
// --------------------------------------------------------
//-----------------------------------------------------------------------------
// ItemName
//
//-----------------------------------------------------------------------------
START_TABLE( k_ESchemaCatalogMain, ItemName, TABLE_PROP_NORMAL )
MEM_FIELD_BIN( unDefIndex, DefIndex, uint16 ) // Item definition index
MEM_FIELD_VAR_CHAR_LEN( VarCharName, Name, 32 ) // Item Name
PRIMARY_KEY_CLUSTERED( 100, unDefIndex )
UNIQUE_FIELD( ItemNameIndex, VarCharName )
WIPE_TABLE_BETWEEN_TESTS( k_EWipePolicyPreserveAlways )
ALLOW_WIPE_TABLE_IN_PRODUCTION( true )
END_TABLE
//-----------------------------------------------------------------------------
// Item
//
//-----------------------------------------------------------------------------
START_TABLE( k_ESchemaCatalogMain, Item, TABLE_PROP_NORMAL )
MEM_FIELD_BIN( ulID, ID, uint64 ) // Item ID
MEM_FIELD_BIN( unAccountID, AccountID, uint32 ) // Item Owner
MEM_FIELD_BIN( unDefIndex, DefIndex, uint16 ) // Item definition index
MEM_FIELD_BIN( unLevel, Level, uint8 ) // Item Level
MEM_FIELD_BIN( nQuality, EQuality, uint8 ) // Item quality (rarity)
MEM_FIELD_BIN( unInventory, Inventory, uint32 ) // App managed int representing inventory placement
MEM_FIELD_BIN( unQuantity, Quantity, uint32 ) // Consumable stack count (ammo, money, etc)
MEM_FIELD_VAR_CHAR_LEN( VarCharCustomName, Name, MAX_ITEM_CUSTOM_NAME_LENGTH+1 ) // User-crafted custom name
PRIMARY_KEY_CLUSTERED( 100, ulID )
INDEX_FIELD( UserAppLookup, unAccountID )
WIPE_TABLE_BETWEEN_TESTS( k_EWipePolicyWipeForAllTests )
ALLOW_WIPE_TABLE_IN_PRODUCTION( false )
END_TABLE
//-----------------------------------------------------------------------------
// AttributeName
//
//-----------------------------------------------------------------------------
START_TABLE( k_ESchemaCatalogMain, AttributeName, TABLE_PROP_NORMAL )
MEM_FIELD_BIN( unAttrDefIndex,AttrDefIndex,uint32 ) // Attribute definition index
MEM_FIELD_VAR_CHAR_LEN( VarCharName, Name, 32 ) // Attribute Name
PRIMARY_KEY_CLUSTERED( 100, unAttrDefIndex )
UNIQUE_FIELD( AttributeNameIndex, VarCharName )
WIPE_TABLE_BETWEEN_TESTS( k_EWipePolicyPreserveAlways )
ALLOW_WIPE_TABLE_IN_PRODUCTION( true )
END_TABLE
//-----------------------------------------------------------------------------
// ItemAttribute
//
//-----------------------------------------------------------------------------
START_TABLE( k_ESchemaCatalogMain, ItemAttribute, TABLE_PROP_NORMAL )
MEM_FIELD_BIN( ulItemID, ItemID, uint64 ) // Item ID
MEM_FIELD_BIN( unAttrDefIndex,AttrDefIndex,uint16 ) // Attribute definition index
MEM_FIELD_BIN( flValue, Value, float ) // Attribute Value
PRIMARY_KEYS_CLUSTERED( 80, ulItemID, unAttrDefIndex )
FOREIGN_KEY_CONSTRAINT( FKItemID, ItemID, Item, ID, GCSDK::k_EForeignKeyActionCascade, GCSDK::k_EForeignKeyActionCascade )
WIPE_TABLE_BETWEEN_TESTS( k_EWipePolicyWipeForAllTests )
ALLOW_WIPE_TABLE_IN_PRODUCTION( false )
END_TABLE
//-----------------------------------------------------------------------------
// ItemAudit
//
//-----------------------------------------------------------------------------
START_TABLE( k_ESchemaCatalogMain, ItemAudit, TABLE_PROP_NORMAL )
MEM_FIELD_BIN( ulItemID, ItemID, uint64 ) // Item ID
MEM_FIELD_BIN( RTime32Stamp,TimeStamp, RTime32 ) // Time
MEM_FIELD_BIN( eAction, Action, uint8 ) // What Happened
MEM_FIELD_BIN( unOwnerID, OwnerID, uint32 ) // Player who owns the item
MEM_FIELD_BIN( unServerIP, ServerIP, uint32 ) // IP of the server this happened on
MEM_FIELD_BIN( usServerPort,ServerPort, uint16 ) // Port of the server this happened on
MEM_FIELD_BIN( unData, Data, uint32 ) // Additional data for the operation
PRIMARY_KEYS_CLUSTERED( 80, ulItemID, RTime32Stamp, eAction )
INDEX_FIELDS( AccountLookupIndex, unOwnerID, eAction )
WIPE_TABLE_BETWEEN_TESTS( k_EWipePolicyWipeForAllTests )
ALLOW_WIPE_TABLE_IN_PRODUCTION( false )
END_TABLE
//-----------------------------------------------------------------------------
// Recipe
//
//-----------------------------------------------------------------------------
START_TABLE( k_ESchemaCatalogMain, Recipe, TABLE_PROP_NORMAL )
MEM_FIELD_BIN( unAccountID, AccountID, uint32 ) // Recipe Owner
MEM_FIELD_BIN( unDefIndex, DefIndex, uint16 ) // Recipe definition index
PRIMARY_KEYS_CLUSTERED( 100, unDefIndex, unAccountID )
INDEX_FIELD( UserAppLookup, unAccountID )
WIPE_TABLE_BETWEEN_TESTS( k_EWipePolicyWipeForAllTests )
ALLOW_WIPE_TABLE_IN_PRODUCTION( false )
END_TABLE
//-----------------------------------------------------------------------------
// WarDeaths
//
//-----------------------------------------------------------------------------
START_TABLE( k_ESchemaCatalogMain, WarDeaths, TABLE_PROP_NORMAL )
MEM_FIELD_BIN( unVictimID, VictimID, uint32 ) // Player who was killed by the opposite side
MEM_FIELD_BIN( RTime32Stamp,TimeStamp, RTime32 ) // Time this player's session ended
PRIMARY_KEYS_CLUSTERED( 80, unVictimID, RTime32Stamp )
MEM_FIELD_BIN( unSessionDuration, SessionDuration, uint32)// Length of this player's session in seconds
MEM_FIELD_BIN( unSoldierDeaths, SoldierDeaths, uint32 ) // Number of times this player died as a solder to a demoman
MEM_FIELD_BIN( unDemomanDeaths, DemomanDeaths, uint32 ) // Number of times this player died as a demoman to a solder
WIPE_TABLE_BETWEEN_TESTS( k_EWipePolicyWipeForAllTests )
ALLOW_WIPE_TABLE_IN_PRODUCTION( false )
END_TABLE
//-----------------------------------------------------------------------------
// GameAccountClient
//
//-----------------------------------------------------------------------------
START_TABLE( k_ESchemaCatalogMain, GameAccountClient, TABLE_PROP_NORMAL )
MEM_FIELD_BIN( unAccountID, AccountID, uint32 ) // Item Owner
PRIMARY_KEY_CLUSTERED( 80, unAccountID )
MEM_FIELD_BIN( unSoldierKills, SoldierKills, uint32 ) // Number of times this player killed soldiers during the War!
MEM_FIELD_BIN( unDemomanKills, DemomanKills, uint32 ) // Number of times this player killed demomen during the War!
WIPE_TABLE_BETWEEN_TESTS( k_EWipePolicyWipeForAllTests )
ALLOW_WIPE_TABLE_IN_PRODUCTION( false )
END_TABLE
//-----------------------------------------------------------------------------
// GameAccount
//
//-----------------------------------------------------------------------------
START_TABLE( k_ESchemaCatalogMain, GameAccount, TABLE_PROP_NORMAL )
MEM_FIELD_BIN( unAccountID, AccountID, uint32 ) // Account ID of the user
MEM_FIELD_BIN( unRewardPoints, RewardPoints, uint32 ) // number of timed reward points (coplayed minutes) for this user
PRIMARY_KEY_CLUSTERED( 100, unAccountID )
WIPE_TABLE_BETWEEN_TESTS( k_EWipePolicyWipeForAllTests )
ALLOW_WIPE_TABLE_IN_PRODUCTION( false )
END_TABLE
// NEED A CARRIAGE RETURN HERE!
//-------------------------
@@ -0,0 +1,439 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "sensorgrenade_projectile.h"
#include "engine/IEngineSound.h"
#include "keyvalues.h"
#include "weapon_csbase.h"
#include "particle_parse.h"
#if defined( CLIENT_DLL )
#include "c_cs_player.h"
#else
#include "sendproxy.h"
#include "cs_player.h"
#include "bot_manager.h"
#include "cs_bot.h"
#endif
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
#if defined( CLIENT_DLL )
IMPLEMENT_CLIENTCLASS_DT( C_SensorGrenadeProjectile, DT_SensorGrenadeProjectile, CSensorGrenadeProjectile )
END_RECV_TABLE()
//--------------------------------------------------------------------------------------------------------
void C_SensorGrenadeProjectile::OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect )
{
if ( FStrEq( pszParticleName, "weapon_sensorgren_detlight" ) )
{
m_sensorgrenadeParticleEffect = pNewParticleEffect;
}
}
//--------------------------------------------------------------------------------------------------------
void C_SensorGrenadeProjectile::OnParticleEffectDeleted( CNewParticleEffect *pParticleEffect )
{
if ( m_sensorgrenadeParticleEffect == pParticleEffect )
{
m_sensorgrenadeParticleEffect = NULL;
}
}
//--------------------------------------------------------------------------------------------------------
bool C_SensorGrenadeProjectile::Simulate( void )
{
// we are still moving
if ( GetAbsVelocity().Length() > 0.1f )
{
return true;
}
if ( !m_sensorgrenadeParticleEffect.IsValid() )
{
DispatchParticleEffect( "weapon_sensorgren_detlight", PATTACH_POINT_FOLLOW, this, "Wick" );
}
else
{
m_sensorgrenadeParticleEffect->SetSortOrigin( GetAbsOrigin() );
m_sensorgrenadeParticleEffect->SetNeedsBBoxUpdate( true );
}
BaseClass::Simulate();
return true;
}
#else // GAME_DLL
#define GRENADE_MODEL "models/Weapons/w_eq_sensorgrenade_thrown.mdl"
LINK_ENTITY_TO_CLASS( tagrenade_projectile, CSensorGrenadeProjectile );
PRECACHE_REGISTER( tagrenade_projectile );
IMPLEMENT_SERVERCLASS_ST( CSensorGrenadeProjectile, DT_SensorGrenadeProjectile )
END_SEND_TABLE()
BEGIN_DATADESC( CSensorGrenadeProjectile )
DEFINE_THINKFUNC( Think_Arm ),
DEFINE_THINKFUNC( Think_Remove ),
DEFINE_THINKFUNC( SensorThink )
END_DATADESC()
// --------------------------------------------------------------------------------------------------- //
// CFlashbangProjectile implementation.
// --------------------------------------------------------------------------------------------------- //
CSensorGrenadeProjectile* CSensorGrenadeProjectile::Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
const CCSWeaponInfo& weaponInfo )
{
CSensorGrenadeProjectile *pGrenade = ( CSensorGrenadeProjectile* )CBaseEntity::Create( "tagrenade_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->SetTimer( 2.0f );
pGrenade->SetAbsVelocity( velocity );
pGrenade->SetupInitialTransmittedGrenadeVelocity( velocity );
pGrenade->SetThrower( pOwner );
pGrenade->m_flDamage = 1.0f; // 25 = 1/4 of HEGrenade Damage
pGrenade->m_DmgRadius = pGrenade->m_flDamage * 3.5f; // Changing damage will change the radius
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
pGrenade->SetAbsAngles( pOwner->EyeAngles() + QAngle( -80, 40, 0 ) );
QAngle angRotationVel = QAngle( RandomFloat(100,200), RandomFloat(-100,200), RandomFloat(-100,200) );
pGrenade->SetLocalAngularVelocity( angRotationVel );
pGrenade->SetTouch( &CSensorGrenadeProjectile::BounceTouch );
pGrenade->SetGravity( BaseClass::GetGrenadeGravity() );
pGrenade->SetFriction( BaseClass::GetGrenadeFriction() );
pGrenade->SetElasticity( BaseClass::GetGrenadeElasticity() );
pGrenade->m_pWeaponInfo = &weaponInfo;
ASSERT(pOwner != NULL);
//pGrenade->SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
return pGrenade;
}
void CSensorGrenadeProjectile::SetTimer( float timer )
{
SetThink( &CSensorGrenadeProjectile::Think_Arm );
SetNextThink( gpGlobals->curtime + timer );
m_fNextDetectPlayerSound = gpGlobals->curtime;
TheBots->SetGrenadeRadius( this, 0.0f );
}
void CSensorGrenadeProjectile::Think_Arm( void )
{
#if 1
if ( GetAbsVelocity().Length() > 0.2f )
{
// Still moving. Don't detonate yet.
SetNextThink( gpGlobals->curtime + 0.2f );
return;
}
#endif // 0
m_fExpireTime = gpGlobals->curtime + 2.0f; // TODO: Make this Data Driven
SetThink( &CSensorGrenadeProjectile::SensorThink );
//TheBots->SetGrenadeRadius( this, SensorGrenadeGrenadeRadius );
SensorThink(); // This will handling the 'Detonate'
}
void CSensorGrenadeProjectile::Think_Remove( void )
{
UTIL_Remove( this );
}
void CSensorGrenadeProjectile::Detonate( void )
{
// [mlowrance] The SensorGrenade is handling it's own detonate.
Assert(!"SensorGrenade grenade handles its own detonation");
}
void CSensorGrenadeProjectile::SensorThink( void )
{
// tell the bots about the gunfire
CCSPlayer *pThrower = ToCSPlayer( GetThrower() );
if ( !pThrower )
return;
if ( gpGlobals->curtime > m_fNextDetectPlayerSound )
{
EmitSound( "Sensor.WarmupBeep" );
m_fNextDetectPlayerSound = gpGlobals->curtime + 1.0f; // TODO: Make this Data Driven
}
if ( gpGlobals->curtime < m_fExpireTime )
{
SetNextThink( gpGlobals->curtime + 0.1f );
}
else
{
// [mlowrance] Do the damage on Despawn and post event
CCSPlayer *player = ToCSPlayer( GetThrower() );
if ( player )
{
IGameEvent * event = gameeventmanager->CreateEvent( "tagrenade_detonate" );
if ( event )
{
event->SetInt( "userid", player->GetUserID() );
event->SetInt( "entityid", this->entindex() );
event->SetFloat( "x", GetAbsOrigin().x );
event->SetFloat( "y", GetAbsOrigin().y );
event->SetFloat( "z", GetAbsOrigin().z );
gameeventmanager->FireEvent( event );
}
}
TheBots->RemoveGrenade( this );
DispatchParticleEffect( "weapon_sensorgren_detonate", PATTACH_POINT, this, "Wick" );
EmitSound( "Sensor.Detonate" );
DoDetectWave();
//BaseClass::Detonate();
}
}
void CSensorGrenadeProjectile::DoDetectWave( void )
{
// tell the bots about the gunfire
CCSPlayer *pThrower = ToCSPlayer( GetThrower() );
if ( !pThrower )
return;
for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
if ( !pPlayer || !pPlayer->IsAlive() || !pThrower->IsOtherEnemy( pPlayer ) )
continue;
Vector vDelta = pPlayer->EyePosition() - GetAbsOrigin();
float flDistance = vDelta.Length();
float flMaxTraceDist = 1600;
if ( flDistance <= flMaxTraceDist )
{
trace_t tr;
//if ( pCSPlayer->IsAlive() && ( flTargetIDCone > flViewCone ) && !bShowAllNamesForSpec )
{
if ( TheCSBots()->IsLineBlockedBySmoke( pPlayer->EyePosition(), GetAbsOrigin(), 1.0f ) )
{
// if we are outside half the max dist and don't trace, dont show
if ( flDistance > (flMaxTraceDist/2) )
continue;
}
UTIL_TraceLine( pPlayer->EyePosition(), GetAbsOrigin(), MASK_VISIBLE, pPlayer, COLLISION_GROUP_DEBRIS, &tr );
if ( tr.fraction != 1 )
{
trace_t tr2;
UTIL_TraceLine( pPlayer->GetAbsOrigin() + Vector( 0, 0, 16 ), GetAbsOrigin(), MASK_VISIBLE, pPlayer, COLLISION_GROUP_DEBRIS, &tr2 );
if ( tr2.fraction != 1 )
{
// if we are outside half the max dist and don't trace, dont show
if ( flDistance > (flMaxTraceDist/2) )
continue;
}
}
int nThrowerIndex = 0;
for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
if ( pPlayer == pThrower )
{
nThrowerIndex = i;
break;
}
}
DebugDrawLine( WorldSpaceCenter(), pPlayer->WorldSpaceCenter(), 90, 0, 0, true, 1.5f );
pPlayer->SetIsSpotted( true );
pPlayer->SetIsSpottedBy( nThrowerIndex );
pPlayer->m_flDetectedByEnemySensorTime = gpGlobals->curtime;
pPlayer->Blind( 0.02f, 1.0f, 128 );
pPlayer->EmitSound( "Sensor.WarmupBeep" );
}
}
}
SetNextThink( gpGlobals->curtime + 0.25f );
SetThink( &CSensorGrenadeProjectile::Think_Remove );
}
void CSensorGrenadeProjectile::Spawn( void )
{
SetModel( GRENADE_MODEL );
BaseClass::Spawn();
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_NOT_STANDABLE );
}
void CSensorGrenadeProjectile::Precache( void )
{
PrecacheModel( GRENADE_MODEL );
PrecacheScriptSound( "Sensor.Detonate" );
PrecacheScriptSound( "Sensor.WarmupBeep" );
PrecacheScriptSound( "Sensor.Activate" );
PrecacheScriptSound( "Flashbang.Bounce" );
//PrecacheParticleSystem( "weapon_sen_active" );
PrecacheParticleSystem( "weapon_sensorgren_detlight" );
PrecacheParticleSystem( "weapon_sensorgren_detonate" );
BaseClass::Precache();
}
void CSensorGrenadeProjectile::BounceTouch( CBaseEntity *other )
{
if ( other->IsSolidFlagSet( FSOLID_TRIGGER | FSOLID_VOLUME_CONTENTS ) )
return;
// don't hit the guy that launched this grenade
if ( other == GetThrower() )
return;
if ( FClassnameIs( other, "func_breakable" ) )
{
return;
}
if ( FClassnameIs( other, "func_breakable_surf" ) )
{
return;
}
// don't detonate on ladders
if ( FClassnameIs( other, "func_ladder" ) )
{
return;
}
// Deal car alarms direct damage to set them off - flames won't do so
if ( FClassnameIs( other, "prop_car_alarm" ) || FClassnameIs( other, "prop_car_glass" ) )
{
CTakeDamageInfo info( this, GetThrower(), 10, DMG_GENERIC );
other->OnTakeDamage( info );
}
const trace_t &hitTrace = GetTouchTrace();
if ( hitTrace.m_pEnt && hitTrace.m_pEnt->MyCombatCharacterPointer() )
{
// don't break if we hit an actor - wait until we hit the environment
return;
}
else
{
SetAbsVelocity( Vector( 0, 0, 0) );
SetMoveType(MOVETYPE_NONE);
SetNextThink( gpGlobals->curtime + 1.0f );
SetThink( &CSensorGrenadeProjectile::Think_Arm );
EmitSound( "Sensor.Activate" );
m_fExpireTime = gpGlobals->curtime + 15.0f; // TODO: Make this Data Driven
// stick the grenade onto the target surface using the closest rotational alignment to match the in-flight orientation,
// ( like breach charges )
Vector vecSurfNormal = hitTrace.plane.normal.Normalized();
Vector vecProjectileZ = EntityToWorldTransform().GetColumn(Z_AXIS);
// sensor grenades can stick on either of two sides, unlike the breach charges. So they don't need to flip when they land on their 'backs'.
if ( DotProduct( vecSurfNormal, vecProjectileZ ) < 0 )
vecSurfNormal = -vecSurfNormal;
QAngle angSurface;
MatrixAngles( ConcatTransforms( QuaternionMatrix( RotateBetween( vecProjectileZ, vecSurfNormal ) ), EntityToWorldTransform() ), angSurface );
SetAbsAngles( angSurface );
//if ( fabs(hitTrace.plane.normal.Dot(Vector(0,0,1))) > 0.65f )
{
//get the player forward vector
// Vector vecFlatForward;
// VectorCopy( pPlayer->Forward(), vecFlatForward );
// vecFlatForward.z = 0;
//
// //derive c4 forward and right
// Vector vecC4Right = CrossProduct( vecFlatForward.Normalized(), hitTrace.plane.normal );
// Vector vecC4Forward = CrossProduct( vecC4Right, trPlant.plane.normal );
//QAngle angle;
//VectorAngles( hitTrace.plane.normal, angle );
//SetAbsAngles( angle );
//m_hDisplayGrenade = CreatePhysicsProp( GRENADE_MODEL, GetAbsOrigin(), GetAbsOrigin(), NULL, false, "prop_physics_multiplayer" );
/*
m_hDisplayGrenade = ( CBreakableProp * )CBaseEntity::CreateNoSpawn( "prop_physics", GetAbsOrigin(), angle );
CBreakableProp *pDisplay = dynamic_cast< CBreakableProp* >( m_hDisplayGrenade.Get() );
if ( pDisplay )
{
pDisplay->KeyValue( "fademindist", "-1" );
pDisplay->KeyValue( "fademaxdist", "0" );
pDisplay->KeyValue( "fadescale", "1" );
pDisplay->KeyValue( "inertiaScale", "1.0" );
pDisplay->KeyValue( "physdamagescale", "0.1" );
//pDisplay->SetPhysicsMode( PHYSICS_MULTIPLAYER_SOLID );
pDisplay->SetModel( GRENADE_MODEL );
pDisplay->SetSolid( SOLID_BBOX );
pDisplay->AddSolidFlags( FSOLID_NOT_STANDABLE );
pDisplay->AddSpawnFlags( SF_PHYSPROP_MOTIONDISABLED );
pDisplay->Precache();
DispatchSpawn( pDisplay );
pDisplay->Activate();
// disable the parent model
SetModelName( NULL_STRING );//invisible
SetSolid( SOLID_NONE );
}
*/
}
/*
// only detonate on surfaces less steep than this
const float kMinCos = cosf( DEG2RAD( weapon_molotov_maxdetonateslope.GetFloat() ) );
if ( hitTrace.plane.normal.z >= kMinCos )
{
//Stick();
}
*/
}
}
//TODO: Let physics handle the sound!
void CSensorGrenadeProjectile::BounceSound( void )
{
EmitSound( "Flashbang.Bounce" );
}
#endif // GAME_DLL
@@ -0,0 +1,84 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef SENSORGRENADE_PROJECTILE_H
#define SENSORGRENADE_PROJECTILE_H
#ifdef _WIN32
#pragma once
#endif
#include "basecsgrenade_projectile.h"
#if defined( CLIENT_DLL )
#include "c_props.h"
#else // GAME_DLL
#include "props.h"
#endif
#if defined( CLIENT_DLL )
class C_SensorGrenadeProjectile : public C_BaseCSGrenadeProjectile//, public C_BreakableProp
{
public:
DECLARE_CLASS( C_SensorGrenadeProjectile, C_BaseCSGrenadeProjectile );
DECLARE_NETWORKCLASS();
virtual bool Simulate( void );
virtual void OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect );
virtual void OnParticleEffectDeleted( CNewParticleEffect *pParticleEffect );
private:
CUtlReference<CNewParticleEffect> m_sensorgrenadeParticleEffect;
};
#else // GAME_DLL
struct SensorGrenadeWeaponProfile;
class CSensorGrenadeProjectile : public CBaseCSGrenadeProjectile//, public CBreakableProp
{
public:
DECLARE_CLASS( CSensorGrenadeProjectile, CBaseCSGrenadeProjectile );
DECLARE_NETWORKCLASS();
DECLARE_DATADESC();
// Overrides.
public:
virtual void Spawn( void );
virtual void Precache( void );
virtual void Detonate( void );
virtual void BounceTouch( CBaseEntity *other );
virtual void BounceSound( void );
virtual GrenadeType_t GetGrenadeType( void ) { return GRENADE_TYPE_SENSOR; }
// Grenade stuff.
static CSensorGrenadeProjectile* Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
const CCSWeaponInfo& weaponInfo );
private:
void Think_Arm( void );
void Think_Remove( void );
void SensorThink( void );
void SetTimer( float timer );
void DoDetectWave( void );
float m_fExpireTime;
float m_fNextDetectPlayerSound;
EHANDLE m_hDisplayGrenade;
};
#endif // GAME_DLL
#endif // SENSORGRENADE_PROJECTILE_H
@@ -0,0 +1,366 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "smokegrenade_projectile.h"
#include "weapon_csbase.h"
#include "particle_parse.h"
#if defined( CLIENT_DLL )
#include "c_cs_player.h"
#else
#include "sendproxy.h"
#include "particle_smokegrenade.h"
#include "cs_player.h"
#include "keyvalues.h"
#include "bot_manager.h"
#include "Effects/inferno.h"
#endif
#define GRENADE_MODEL "models/Weapons/w_eq_smokegrenade_thrown.mdl"
#if defined( CLIENT_DLL )
IMPLEMENT_CLIENTCLASS_DT( C_SmokeGrenadeProjectile, DT_SmokeGrenadeProjectile, CSmokeGrenadeProjectile )
RecvPropBool( RECVINFO( m_bDidSmokeEffect ) ),
RecvPropInt( RECVINFO( m_nSmokeEffectTickBegin ) )
END_RECV_TABLE()
C_SmokeGrenadeProjectile::~C_SmokeGrenadeProjectile()
{
RemoveSmokeGrenadeHandle( this );
}
void C_SmokeGrenadeProjectile::PostDataUpdate( DataUpdateType_t type )
{
BaseClass::PostDataUpdate( type );
}
void C_SmokeGrenadeProjectile::OnDataChanged( DataUpdateType_t updateType )
{
if ( ( m_nSmokeEffectTickBegin || m_bDidSmokeEffect ) && !m_bSmokeEffectSpawned )
{
SpawnSmokeEffect();
// And the smoke grenade particle began! - every call but the first is extraneous here
AddSmokeGrenadeHandle( this );
}
}
void C_SmokeGrenadeProjectile::SpawnSmokeEffect( )
{
if ( !m_bSmokeEffectSpawned )
{
m_bSmokeEffectSpawned = true;
CNewParticleEffect *pSmokeEffect = NULL;
// Used to be:
int nUseMethod = 2;
if ( nUseMethod == 0 )
{
// this is the closest to the old method; it doesn't let us correct the lifetime of the particle system in case of full frame update
DispatchParticleEffect( "explosion_smokegrenade", GetAbsOrigin(), QAngle( 0, 0, 0 ) );// note QAngle(0,0,0). But we need to simulate the particle effect forward sometimes, so we need to use different API now.
}
else
{
Vector vOrigin = GetNetworkOrigin();
if ( nUseMethod == 1 )
{
// This method works, but isn't the closest to the old method. The old method used CNewParticleEffect::CreateOrAggregate() API in its guts, but aggregation is implicitly disabled by explosion_smokegrenade particle definition as of Dec 2015 in CSGO staging.
pSmokeEffect = ParticleProp()->Create( "explosion_smokegrenade", PATTACH_CUSTOMORIGIN );
}
else
{
// The old method used CNewParticleEffect::CreateOrAggregate() API in its guts, so this is the closest method to create smoke to the old method, but it's not been tested in trunk
pSmokeEffect = CNewParticleEffect::CreateOrAggregate( NULL, "explosion_smokegrenade", vOrigin );
}
if ( pSmokeEffect )
{
pSmokeEffect->SetSortOrigin( vOrigin );
pSmokeEffect->SetControlPoint( 0, vOrigin );
pSmokeEffect->SetControlPoint( 1, vOrigin );
pSmokeEffect->SetControlPointOrientation( 0, Vector( 1, 0, 0 ), Vector( 0, -1, 0 ), Vector( 0, 0, 1 ) );
}
}
if ( m_nSmokeEffectTickBegin )
{
int nSkipFrames = gpGlobals->tickcount - m_nSmokeEffectTickBegin;
if ( nSkipFrames > 4 && pSmokeEffect )
{
//Note: pSmokeEffect->Simulate( flSkipSeconds ); would be ideal, but it doesn't work well for long intervals. SkipToTime would be even better but it will extinguish the particle effect if it skips past 2 seconds due to some perf heuristic, and it's not clear if it skips correctly either.
// this doesn't happen often, and when it does, it's on connection or on replay begin/end, so a little hitch shouldn't be a problem.
for ( int i = 2; i < nSkipFrames; i += 2 )
pSmokeEffect->Simulate( gpGlobals->interval_per_tick * 2 );
}
}
}
}
#else // GAME_DLL
LINK_ENTITY_TO_CLASS( smokegrenade_projectile, CSmokeGrenadeProjectile );
PRECACHE_REGISTER( smokegrenade_projectile );
IMPLEMENT_SERVERCLASS_ST( CSmokeGrenadeProjectile, DT_SmokeGrenadeProjectile )
SendPropBool( SENDINFO( m_bDidSmokeEffect ) ),
SendPropInt( SENDINFO( m_nSmokeEffectTickBegin ) )
END_SEND_TABLE()
BEGIN_DATADESC( CSmokeGrenadeProjectile )
DEFINE_THINKFUNC( Think_Detonate ),
DEFINE_THINKFUNC( Think_Fade ),
DEFINE_THINKFUNC( Think_Remove )
END_DATADESC()
CSmokeGrenadeProjectile* CSmokeGrenadeProjectile::Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
const CCSWeaponInfo& weaponInfo )
{
CSmokeGrenadeProjectile *pGrenade = (CSmokeGrenadeProjectile*)CBaseEntity::Create( "smokegrenade_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->SetTimer( 1.5 );
pGrenade->SetAbsVelocity( velocity );
pGrenade->SetupInitialTransmittedGrenadeVelocity( velocity );
pGrenade->SetThrower( pOwner );
pGrenade->SetGravity( 0.55 );
pGrenade->SetFriction( 0.7 );
pGrenade->m_flDamage = 100;
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
pGrenade->ApplyLocalAngularVelocityImpulse( angVelocity );
pGrenade->SetTouch( &CBaseGrenade::BounceTouch );
pGrenade->SetGravity( BaseClass::GetGrenadeGravity() );
pGrenade->SetFriction( BaseClass::GetGrenadeFriction() );
pGrenade->SetElasticity( BaseClass::GetGrenadeElasticity() );
pGrenade->m_bDidSmokeEffect = false;
pGrenade->m_nSmokeEffectTickBegin = 0;
pGrenade->m_flLastBounce = 0;
pGrenade->m_vSmokeColor = weaponInfo.GetSmokeColor();
pGrenade->m_pWeaponInfo = &weaponInfo;
pGrenade->SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
return pGrenade;
}
void CSmokeGrenadeProjectile::SetTimer( float timer )
{
SetThink( &CSmokeGrenadeProjectile::Think_Detonate );
SetNextThink( gpGlobals->curtime + timer );
TheBots->SetGrenadeRadius( this, 0.0f );
}
void CSmokeGrenadeProjectile::Think_Detonate()
{
if ( GetAbsVelocity().Length() > 0.1 )
{
// Still moving. Don't detonate yet.
SetNextThink( gpGlobals->curtime + 0.2 );
return;
}
SmokeDetonate();
}
void CSmokeGrenadeProjectile::SmokeDetonate( void )
{
TheBots->SetGrenadeRadius( this, SmokeGrenadeRadius );
// Ok, we've stopped rolling or whatever. Now detonate.
// Make sure all players get the message about this smoke effect.
// This fixes an exploit where a player could enter a room where others were seeing smoke and he wasn't
// because he wasn't in the PVS when the smoke effect started.
m_nSmokeEffectTickBegin = gpGlobals->tickcount; // client will star the explosion_smokegrenade particle effect at AbsOrigin
//tell the hostages about the smoke!
CBaseEntity *pEntity = NULL;
variant_t var; //send the location of the smoke?
var.SetVector3D( GetAbsOrigin() );
while ( ( pEntity = gEntList.FindEntityByClassname( pEntity, "hostage_entity" ) ) != NULL)
{
//send to hostages that have a resonable chance of being in it while its still smoking
if( (GetAbsOrigin() - pEntity->GetAbsOrigin()).Length() < 1000 )
pEntity->AcceptInput( "smokegrenade", this, this, var, 0 );
}
// tell the bots a smoke grenade has exploded
CCSPlayer *player = ToCSPlayer(GetThrower());
if ( player )
{
IGameEvent * event = gameeventmanager->CreateEvent( "smokegrenade_detonate" );
if ( event )
{
event->SetInt( "userid", player->GetUserID() );
event->SetInt( "entityid", this->entindex() );
event->SetFloat( "x", GetAbsOrigin().x );
event->SetFloat( "y", GetAbsOrigin().y );
event->SetFloat( "z", GetAbsOrigin().z );
gameeventmanager->FireEvent( event );
}
}
// We avoid our base class detonation, so add the ogs record of our explsion here.
// Note: this has to be after the gameevent is fired and serviced by server-side listeners
// so we can run the 'smoke grenade extinguishing infernos' logic and have ogs relevant state set from that.
RecordDetonation();
m_bDidSmokeEffect = true; //<- the old way to signal the start of smoke effect; the new way is to set the particle start tick, so that we can replay and fix the bug when we lose the smoke effect when we connect right after smoke grenade went off
EmitSound( "BaseSmokeEffect.Sound" );
m_nRenderMode = kRenderTransColor;
SetMoveType(MOVETYPE_NONE);
SetNextThink( gpGlobals->curtime + 12.5f );
SetThink( &CSmokeGrenadeProjectile::Think_Fade );
SetSolid( SOLID_NONE );
}
void CSmokeGrenadeProjectile::RemoveGrenadeFromLists( void )
{
TheBots->RemoveGrenade( this );
SetModelName( NULL_STRING );//invisible
SetSolid( SOLID_NONE );
CCSPlayer *player = ToCSPlayer(GetThrower());
if ( player )
{
IGameEvent * event = gameeventmanager->CreateEvent( "smokegrenade_expired" );
if ( event )
{
event->SetInt( "userid", player->GetUserID() );
event->SetInt( "entityid", this->entindex() );
event->SetFloat( "x", GetAbsOrigin().x );
event->SetFloat( "y", GetAbsOrigin().y );
event->SetFloat( "z", GetAbsOrigin().z );
gameeventmanager->FireEvent( event );
}
}
}
// Fade the projectile out over time before making it disappear
void CSmokeGrenadeProjectile::Think_Fade()
{
SetNextThink( gpGlobals->curtime );
byte a = GetRenderAlpha();
a -= 1;
SetRenderAlpha( a );
if ( !a )
{
//RemoveGrenadeFromLists();
SetNextThink( gpGlobals->curtime + 1.0 );
SetThink( &CSmokeGrenadeProjectile::Think_Remove ); // Spit out smoke for 10 seconds.
}
}
void CSmokeGrenadeProjectile::Think_Remove()
{
RemoveGrenadeFromLists();
SetMoveType( MOVETYPE_NONE );
UTIL_Remove( this );
}
//Implement this so we never call the base class,
//but this should never be called either.
void CSmokeGrenadeProjectile::Detonate( void )
{
Assert(!"Smoke grenade handles its own detonation");
}
void CSmokeGrenadeProjectile::Spawn()
{
SetModel( GRENADE_MODEL );
BaseClass::Spawn();
SetBodygroupPreset( "thrown" );
}
void CSmokeGrenadeProjectile::Precache()
{
PrecacheModel( GRENADE_MODEL );
PrecacheScriptSound( "BaseSmokeEffect.Sound" );
PrecacheScriptSound( "SmokeGrenade.Bounce" );
BaseClass::Precache();
}
void CSmokeGrenadeProjectile::OnBounced( void )
{
if ( m_flLastBounce >= ( gpGlobals->curtime - 3*gpGlobals->interval_per_tick ) )
return;
m_flLastBounce = gpGlobals->curtime;
//
// if the smoke grenade is above ground, trace down to the ground and see where it would end up?
//
Vector posDropSmoke = GetAbsOrigin();
trace_t trSmokeTrace;
UTIL_TraceLine( posDropSmoke, posDropSmoke - Vector( 0, 0, SmokeGrenadeRadius ), ( MASK_PLAYERSOLID & ~CONTENTS_PLAYERCLIP ),
this, COLLISION_GROUP_PROJECTILE, &trSmokeTrace );
if ( !trSmokeTrace.startsolid )
{
if ( trSmokeTrace.fraction >= 1.0f )
return; // this smoke cannot drop enough to cause extinguish
if ( trSmokeTrace.fraction > 0.001f )
posDropSmoke = trSmokeTrace.endpos;
}
//
// See if it touches any inferno?
//
const int maxEnts = 64;
CBaseEntity *list[ maxEnts ];
int count = UTIL_EntitiesInSphere( list, maxEnts, GetAbsOrigin(), 512, FL_ONFIRE );
for( int i=0; i<count; ++i )
{
if (list[i] == NULL || list[i] == this)
continue;
CInferno* pInferno = dynamic_cast<CInferno*>( list[i] );
if ( pInferno && pInferno->BShouldExtinguishSmokeGrenadeBounce( this, posDropSmoke ) )
{
if ( posDropSmoke != GetAbsOrigin() )
{
const QAngle qAngOriginZero = vec3_angle;
const Vector vVelocityZero = vec3_origin;
Teleport( &posDropSmoke, &qAngOriginZero, &vVelocityZero );
}
SmokeDetonate();
break;
}
}
}
void CSmokeGrenadeProjectile::BounceSound( void )
{
if ( !m_bDidSmokeEffect )
{
EmitSound( "SmokeGrenade.Bounce" );
}
}
#endif
@@ -0,0 +1,86 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef SMOKEGRENADE_PROJECTILE_H
#define SMOKEGRENADE_PROJECTILE_H
#ifdef _WIN32
#pragma once
#endif
#include "basecsgrenade_projectile.h"
#if defined( CLIENT_DLL )
class C_SmokeGrenadeProjectile : public C_BaseCSGrenadeProjectile
{
public:
DECLARE_CLASS( C_SmokeGrenadeProjectile, C_BaseCSGrenadeProjectile );
DECLARE_NETWORKCLASS();
C_SmokeGrenadeProjectile() {}
virtual ~C_SmokeGrenadeProjectile();
virtual void PostDataUpdate( DataUpdateType_t updateType ) OVERRIDE;
virtual void OnDataChanged( DataUpdateType_t updateType ) OVERRIDE;
virtual GrenadeType_t GetGrenadeType( void ) { return GRENADE_TYPE_SMOKE; }
void SpawnSmokeEffect();
CNetworkVar( int, m_nSmokeEffectTickBegin );
CNetworkVar( bool, m_bDidSmokeEffect );
bool m_bSmokeEffectSpawned;
};
#else // GAME_DLL
class CSmokeGrenadeProjectile : public CBaseCSGrenadeProjectile
{
public:
DECLARE_CLASS( CSmokeGrenadeProjectile, CBaseCSGrenadeProjectile );
DECLARE_NETWORKCLASS();
public:
DECLARE_DATADESC();
// Overrides.
public:
virtual void Spawn();
virtual void Precache();
virtual void Detonate();
virtual void OnBounced( void );
virtual void BounceSound( void );
void Think_Detonate();
void Think_Fade();
void Think_Remove();
void SmokeDetonate( void );
void RemoveGrenadeFromLists( void );
virtual GrenadeType_t GetGrenadeType( void ) { return GRENADE_TYPE_SMOKE; }
virtual int UpdateTransmitState() { return SetTransmitState( FL_EDICT_ALWAYS ); }
// Grenade stuff.
public:
static CSmokeGrenadeProjectile* Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
const CCSWeaponInfo& weaponInfo );
void SetTimer( float timer );
CNetworkVar( int, m_nSmokeEffectTickBegin );
CNetworkVar( bool, m_bDidSmokeEffect );
Vector m_vSmokeColor;
float m_flLastBounce;
};
#endif // GAME_DLL
#endif // SMOKEGRENADE_PROJECTILE_H
Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

@@ -0,0 +1,26 @@
// Builds static array of structs for adding special cases for viewmodel addons depending on
// the character model needs (eg skintone, different sleeves when wearing econ gloves, etc)
//
// ORDER IS IMPORTANT: Finds the first rule that has 'model substring' as part of the query model name and early outs.
// More narrow matches should go before broader matches, so tm_professional_var4 before tm_professional.
// model substring, skin index, default glove model, sleeve, arms to use when wearing econ gloves
CFG( tm_leet, 0, models/weapons/v_models/arms/glove_fingerless/v_glove_fingerless.mdl, /*none*/, /*none*/ )
CFG( tm_phoenix_varianta, 3, models/weapons/v_models/arms/glove_fullfinger/v_glove_fullfinger.mdl, /*none*/, /*none*/ )
CFG( tm_phoenix_variantb, 2, models/weapons/v_models/arms/glove_fullfinger/v_glove_fullfinger.mdl, /*none*/, /*none*/ )
CFG( tm_phoenix, 0, models/weapons/v_models/arms/glove_fullfinger/v_glove_fullfinger.mdl, /*none*/, /*none*/ )
CFG( tm_separatist, 0, models/weapons/v_models/arms/glove_fullfinger/v_glove_fullfinger.mdl, models/weapons/v_models/arms/separatist/v_sleeve_separatist.mdl, /*none*/ )
CFG( tm_balkan, 0, models/weapons/v_models/arms/glove_fullfinger/v_glove_fullfinger.mdl, models/weapons/v_models/arms/balkan/v_sleeve_balkan.mdl, /*none*/ )
CFG( tm_professional_var4, 1, models/weapons/v_models/arms/glove_fullfinger/v_glove_fullfinger.mdl, models/weapons/v_models/arms/professional/v_sleeve_professional.mdl, /*none*/ )
CFG( tm_professional, 0, models/weapons/v_models/arms/glove_fullfinger/v_glove_fullfinger.mdl, models/weapons/v_models/arms/professional/v_sleeve_professional.mdl, /*none*/ )
CFG( tm_anarchist, 0, models/weapons/v_models/arms/anarchist/v_glove_anarchist.mdl, /*none*/, models/weapons/v_models/arms/anarchist/v_sleeve_anarchist.mdl )
CFG( tm_pirate, 1, models/weapons/v_models/arms/bare/v_bare_hands.mdl, models/weapons/v_models/arms/pirate/v_pirate_watch.mdl, /*none*/ )
CFG( tm_heavy, 0, models/weapons/v_models/arms/glove_fingerless/v_glove_fingerless.mdl, models/weapons/v_models/arms/balkan/v_sleeve_balkan.mdl, /*none*/ )
CFG( ctm_st6, 0, models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle.mdl, models/weapons/v_models/arms/st6/v_sleeve_st6.mdl, /*none*/ )
CFG( ctm_idf, 0, models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle.mdl, models/weapons/v_models/arms/idf/v_sleeve_idf.mdl, /*none*/ )
CFG( ctm_gign, 0, models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle_blue.mdl, models/weapons/v_models/arms/gign/v_sleeve_gign.mdl, /*none*/ )
CFG( ctm_swat_variantb, 1, models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle_black.mdl, models/weapons/v_models/arms/swat/v_sleeve_swat.mdl, /*none*/ )
CFG( ctm_swat, 0, models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle_black.mdl, models/weapons/v_models/arms/swat/v_sleeve_swat.mdl, /*none*/ )
CFG( ctm_gsg9, 0, models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle_blue.mdl, models/weapons/v_models/arms/gsg9/v_sleeve_gsg9.mdl, /*none*/ )
CFG( ctm_sas, 0, models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle_black.mdl, models/weapons/v_models/arms/sas/v_sleeve_sas.mdl, /*none*/ )
CFG( ctm_fbi, 0, models/weapons/v_models/arms/glove_hardknuckle/v_glove_hardknuckle_black.mdl, models/weapons/v_models/arms/fbi/v_sleeve_fbi.mdl, /*none*/ )
@@ -0,0 +1,704 @@
//========= Copyright 1996-2005, 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"
#include "cs_shareddefs.h"
#ifdef CLIENT_DLL
#include "c_cs_player.h"
#include "HUD/sfweaponselection.h"
#include "c_rumble.h"
#include "rumble_shared.h"
#else
#include "cs_player.h"
#include "items.h"
#include "cs_gamestats.h"
#endif
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
#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_bIsHeldByPlayer) ),
SendPropBool( SENDINFO(m_bPinPulled) ),
SendPropFloat( SENDINFO(m_fThrowTime), 0, SPROP_NOSCALE ),
SendPropBool( SENDINFO( m_bLoopingSoundPlaying ) ),
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
SendPropFloat( SENDINFO(m_flThrowStrength), 0, SPROP_NOSCALE ),
#endif
#else
RecvPropBool( RECVINFO(m_bRedraw) ),
RecvPropBool( RECVINFO(m_bIsHeldByPlayer) ),
RecvPropBool( RECVINFO(m_bPinPulled) ),
RecvPropFloat( RECVINFO(m_fThrowTime) ),
RecvPropBool( RECVINFO( m_bLoopingSoundPlaying ) ),
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
RecvPropFloat( RECVINFO(m_flThrowStrength) ),
#endif
#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_bPinPulled, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
DEFINE_PRED_FIELD( m_flThrowStrength, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
#endif
END_PREDICTION_DATA()
#endif
LINK_ENTITY_TO_CLASS_ALIASED( weapon_basecsgrenade, BaseCSGrenade );
#ifndef CLIENT_DLL
ConVar sv_ignoregrenaderadio( "sv_ignoregrenaderadio", "0", FCVAR_RELEASE, "Turn off Fire in the hole messages" );
#endif
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
#define GRENADE_SECONDARY_DAMPENING 0.3f
#define GRENADE_SECONDARY_LOWER 12.0f
#define GRENADE_SECONDARY_TRANSITION 1.3f
#define GRENADE_SECONDARY_INTERP 2.0f
#endif
CBaseCSGrenade::CBaseCSGrenade()
{
m_bRedraw = false;
m_bIsHeldByPlayer = false;
m_bPinPulled = false;
m_fThrowTime = 0;
m_bLoopingSoundPlaying = false;
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
m_flThrowStrength = 1.0f;
m_flThrowStrengthClientSmooth = 1.0f;
#endif
#ifndef CLIENT_DLL
m_bHasEmittedProjectile = false;
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseCSGrenade::Precache()
{
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseCSGrenade::Deploy()
{
m_bRedraw = false;
m_bIsHeldByPlayer = true;
m_bPinPulled = false;
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
m_flThrowStrength = 1.0f;
m_flThrowStrengthClientSmooth = 1.0f;
#endif
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();
}
#ifdef CLIENT_DLL
int CBaseCSGrenade::DrawModel( int flags, const RenderableInstance_t &instance )
{
//hide the grenade that's in the player's hand while playing grenade throwing animations
CCSPlayer *pPlayer = GetPlayerOwner();
if ( pPlayer )
{
if ( !pPlayer->m_bUseNewAnimstate && pPlayer->m_PlayerAnimState && pPlayer->m_PlayerAnimState->ShouldHideGrenadeDuringThrow() )
{
return 0;
}
}
return BaseClass::DrawModel( flags, instance );
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBaseCSGrenade::Holster( CBaseCombatWeapon *pSwitchingTo )
{
m_bRedraw = false;
// we don't want to set m_bIsHeldByPlayer to true because the weapon actually holsters before it's removed from the inventory after the last grenade has been thrown
// this causes a visual bug in the weapon selection UI
m_bPinPulled = false; // when this is holstered make sure the pin isnt pulled.
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
m_flThrowStrength = 1.0f;
m_flThrowStrengthClientSmooth = 1.0f;
#endif
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_bIsHeldByPlayer || m_bPinPulled || m_fThrowTime > 0.0f )
return;
CCSPlayer *pPlayer = GetPlayerOwner();
if ( !pPlayer || pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
return;
// Ensure that the player can use this grenade
if ( !pPlayer->CanUseGrenade( GetCSWeaponID() ) )
{
return;
}
#ifndef CLIENT_DLL
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_GRENADE_PULL_PIN );
#endif
// 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()
{
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
if ( !m_bPinPulled )
{
m_flThrowStrength = 0.0f;
m_flThrowStrengthClientSmooth = 0.0f;
}
if ( CSGameRules()->IsFreezePeriod() ) // Don't let Brian molotov the team during freezetime
return;
PrimaryAttack();
return;
#endif
/*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:
// Input : *pPicker -
//-----------------------------------------------------------------------------
void CBaseCSGrenade::OnPickedUp( CBaseCombatCharacter *pNewOwner )
{
BaseClass::OnPickedUp( pNewOwner );
#if !defined( CLIENT_DLL )
if ( pNewOwner )
{
m_bIsHeldByPlayer = true;
}
#endif
}
void CBaseCSGrenade::ItemPreFrame()
{
BaseClass::ItemPreFrame();
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner == NULL )
return;
#ifdef CLIENT_DLL
//we want to control the grenade model's visibility so opt out of the fast path
if (GetBaseAnimating())
GetBaseAnimating()->SetAllowFastPath(false);
#endif
}
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
float CBaseCSGrenade::ApproachThrownStrength()
{
m_flThrowStrengthClientSmooth = Approach(
m_flThrowStrength,
m_flThrowStrengthClientSmooth,
gpGlobals->frametime * GRENADE_SECONDARY_INTERP
);
return m_flThrowStrengthClientSmooth;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseCSGrenade::ItemPostFrame()
{
CCSPlayer *pPlayer = GetPlayerOwner();
if ( !pPlayer )
return;
CBaseViewModel *vm = pPlayer->GetViewModel( m_nViewModelIndex );
if ( !vm )
return;
bool bPrimaryHeld = (pPlayer->m_nButtons & IN_ATTACK) != 0;
bool bSecondaryHeld = (pPlayer->m_nButtons & IN_ATTACK2) != 0;
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
if ( m_bPinPulled && ( bPrimaryHeld || bSecondaryHeld ) )
{
float flIdealThrowStrength = 0.5f;
if ( bPrimaryHeld )
flIdealThrowStrength += 0.5f;
if ( bSecondaryHeld )
flIdealThrowStrength -= 0.5f;
m_flThrowStrength = Approach( flIdealThrowStrength, m_flThrowStrength, gpGlobals->frametime * GRENADE_SECONDARY_TRANSITION );
}
#endif
// If they let go of the fire buttons, they want to throw the grenade.
if ( m_bPinPulled && !(bPrimaryHeld) && !(bSecondaryHeld) )
{
#ifndef CLIENT_DLL
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
if ( IsThrownUnderhand() )
{
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_THROW_GRENADE_UNDERHAND );
}
else
#endif
{
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_THROW_GRENADE );
}
#endif
StartGrenadeThrow();
MDLCACHE_CRITICAL_SECTION();
m_bPinPulled = false;
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
if ( IsThrownUnderhand() )
{
SendWeaponAnim( ACT_VM_RELEASE );
}
else
#endif
{
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 ( IsWeaponClassname( weaponName ) )
{
weaponName += WEAPON_CLASSNAME_PREFIX_LENGTH;
}
event->SetInt( "userid", pPlayer->GetUserID() );
event->SetString( "weapon", weaponName );
event->SetBool( "silenced", false );
gameeventmanager->FireEvent( event );
}
#else
RumbleEffect( XBX_GetUserId( pPlayer->GetSplitScreenPlayerSlot() ), RUMBLE_CROWBAR_SWING, 0, RUMBLE_FLAG_RESTART );
#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_bIsHeldByPlayer )
{
// Has the throw animation finished playing
if( m_flTimeWeaponIdle < gpGlobals->curtime )
{
// if we're officially out of grenades, ditch this weapon
int nAmmoCount = pPlayer->GetAmmoCount(m_iPrimaryAmmoType);
if( nAmmoCount <= 0 )
{
pPlayer->Weapon_Drop( this, NULL, NULL );
#ifndef CLIENT_DLL
//pPlayer->RemoveWeaponOnPlayer( this );
UTIL_Remove(this);
#endif
}
else
{
pPlayer->SwitchToNextBestWeapon( this );
}
#if defined (CLIENT_DLL)
// when a grenade is removed, force the local player to update thier inventory screen
C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
if ( pLocalPlayer && pLocalPlayer == pPlayer )
{
SFWeaponSelection *pHudWS = GET_HUDELEMENT( SFWeaponSelection );
if ( pHudWS )
{
int nAmmoCount = pPlayer->GetAmmoCount(m_iPrimaryAmmoType);
if ( nAmmoCount <= 0 )
{
pHudWS->ShowAndUpdateSelection( WEPSELECT_DROP, this );
}
else
{
// we need to tell the hud that this weapon still exists and then update the selected weapon
pHudWS->ShowAndUpdateSelection( WEPSELECT_PICKUP, 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_bIsHeldByPlayer = false;
m_fThrowTime = 0.0f;
}
void CBaseCSGrenade::ThrowGrenade()
{
m_bRedraw = true;
m_bIsHeldByPlayer = false;
m_fThrowTime = 0.0f;
CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection();
if ( pHudSelection )
{
pHudSelection->OnWeaponDrop( this );
}
}
void CBaseCSGrenade::StartGrenadeThrow()
{
m_fThrowTime = gpGlobals->curtime + 0.1f;
}
#else
BEGIN_DATADESC( CBaseCSGrenade )
DEFINE_FIELD( m_bRedraw, FIELD_BOOLEAN ),
DEFINE_FIELD( m_bIsHeldByPlayer, 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;
CBroadcastRecipientFilter filter;
CSoundParameters params;
if ( GetParametersForSound( GetShootSound( SINGLE ), params, NULL ) )
{
//CPASAttenuationFilter filter( this );
EmitSound( filter, entindex(), GetShootSound( SINGLE ));
}
//WeaponSound(SINGLE, gpGlobals->curtime + 3.0f);
}
void CBaseCSGrenade::ThrowGrenade()
{
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if ( !pPlayer )
{
Assert( false );
return;
}
QAngle angThrow = pPlayer->GetFinalAimAngle();
if ( angThrow[PITCH] > 90.0f )
{
angThrow[PITCH] -= 360.0f;
}
else if ( angThrow[PITCH] < -90.0f )
{
angThrow[PITCH] += 360.0f;
}
AssertMsg( angThrow[PITCH] <= 90.0f && angThrow[PITCH] >= -90.0f, "Grenade throw pitch angle must be between -90 and 90 for the adustments to work.");
// NB. a pitch of +90 is looking straight down, -90 is looking straight up
// add a 10 degrees upwards angle to the throw when looking horizontal, lerp the upwards boost to 0 at the pitch extremes
angThrow[PITCH] -= 10.0f * (90.0f - fabsf(angThrow[PITCH])) / 90.0f;
const float kBaseVelocity = GetThrowVelocity();
//const float kThrowVelocityClampRatio = 750.0f / 540.0f; // from original CSS values
//float flVel = clamp((90 - angThrow.x) / 90, 0.0f, kThrowVelocityClampRatio) * kBaseVelocity;
float flVel = clamp( (kBaseVelocity * 0.9f), 15, 750 );
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
//clamp the throw strength ranges just to be sure
float flClampedThrowStrength = m_flThrowStrength;
flClampedThrowStrength = clamp( flClampedThrowStrength, 0.0f, 1.0f );
flVel *= Lerp( flClampedThrowStrength, GRENADE_SECONDARY_DAMPENING, 1.0f );
#endif
Vector vForward;
AngleVectors( angThrow, &vForward );
Vector vecSrc = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset();
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
vecSrc += Vector(0, 0, Lerp( flClampedThrowStrength, -GRENADE_SECONDARY_LOWER, 0.0f ) );
#endif
// 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.
// Wills: Moved the trace length out to 22 inches, then subtract 6. This way we default to 16,
// but pull back 6 from wherever we hit, so we don't emit from EXACTLY inside the close surface, which can lead to
// the grenade penetrating the wall anyway.
trace_t trace;
Vector mins( -2, -2, -2 );
Vector maxs( 2, 2, 2 );
UTIL_TraceHull( vecSrc, vecSrc + vForward * 22, mins, maxs, MASK_SOLID | CONTENTS_GRENADECLIP, pPlayer, COLLISION_GROUP_NONE, &trace );
vecSrc = trace.endpos - (vForward * 6);
Vector vecThrow = vForward * flVel + (pPlayer->GetAbsVelocity() * 1.25);
EmitGrenade( vecSrc, vec3_angle, vecThrow, AngularImpulse(600,random->RandomInt(-1200,1200),0), pPlayer, GetCSWpnData() );
m_bHasEmittedProjectile = true; // Flag the grenade weapon as having emitted a projectile. The 'grenade' is now flying away from the player, so we don't want to drop *this* grenade on death (that'll make a duplicate)
m_bRedraw = true;
m_bIsHeldByPlayer = false;
m_fThrowTime = 0.0f;
CCSPlayer *pCSPlayer = ToCSPlayer( pPlayer );
if ( pCSPlayer )
{
int iWeaponId = GetCSWeaponID();
pCSPlayer->PlayerUsedGrenade( iWeaponId );
if ( !sv_ignoregrenaderadio.GetBool() )
{
if ( iWeaponId == WEAPON_FLASHBANG )
pCSPlayer->Radio( "Radio.Flashbang", "#SFUI_TitlesTXT_Flashbang_in_the_hole", true );
else if ( iWeaponId == WEAPON_SMOKEGRENADE )
pCSPlayer->Radio( "Radio.Smoke", "#SFUI_TitlesTXT_Smoke_in_the_hole", true );
else if ( iWeaponId == WEAPON_MOLOTOV )
pCSPlayer->Radio( "Radio.Molotov", "#SFUI_TitlesTXT_Molotov_in_the_hole", true );
else if ( iWeaponId == WEAPON_INCGRENADE )
pCSPlayer->Radio( "Radio.Incendiary", "#SFUI_TitlesTXT_Incendiary_in_the_hole", true );
else if ( iWeaponId == WEAPON_DECOY )
pCSPlayer->Radio( "Radio.Decoy", "#SFUI_TitlesTXT_Decoy_in_the_hole", true );
else
pCSPlayer->Radio( "Radio.FireInTheHole", "#SFUI_TitlesTXT_Fire_in_the_hole", true );
}
CCS_GameStats.IncrementStat( pCSPlayer, CSSTAT_GRENADES_THROWN, 1 );
}
IGameEvent * event = gameeventmanager->CreateEvent( "grenade_thrown" );
if ( event )
{
const char *weaponName = STRING( m_iClassname );
if ( IsWeaponClassname( weaponName ) )
{
weaponName += WEAPON_CLASSNAME_PREFIX_LENGTH;
}
event->SetInt( "userid", pPlayer->GetUserID() );
event->SetString( "weapon", weaponName );
gameeventmanager->FireEvent( event );
}
}
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, GetCSWpnData() );
CCSPlayer *pCSPlayer = ToCSPlayer( pPlayer );
if( pCSPlayer )
{
CCS_GameStats.IncrementStat( pCSPlayer, CSSTAT_GRENADES_THROWN, 1 );
}
m_bRedraw = true;
m_bIsHeldByPlayer = false;
m_fThrowTime = 0.0f;
}
void CBaseCSGrenade::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, const CCSWeaponInfo& weaponInfo )
{
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,115 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef WEAPON_BASECSGRENADE_H
#define WEAPON_BASECSGRENADE_H
#ifdef _WIN32
#pragma once
#endif
#include "weapon_csbase.h"
#include "cs_shareddefs.h"
#ifdef CLIENT_DLL
#define CBaseCSGrenade C_BaseCSGrenade
#endif
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
#define GRENADE_UNDERHAND_THRESHOLD 0.33f
#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();
bool Reload();
virtual void ItemPostFrame();
virtual void ItemPreFrame();
virtual void OnPickedUp( CBaseCombatCharacter *pNewOwner );
void DecrementAmmo( CBaseCombatCharacter *pOwner );
virtual void StartGrenadeThrow();
virtual void ThrowGrenade();
virtual void DropGrenade();
bool IsPinPulled() const;
bool IsBeingThrown() const { return m_fThrowTime > 0; }
bool IsLoopingSoundPlaying( void ) { return m_bLoopingSoundPlaying; }
void SetLoopingSoundPlaying( bool bPlaying ) { m_bLoopingSoundPlaying = bPlaying; }
// true if grenade has been thrown or dropped
bool GetIsThrown( void ) { return !m_bIsHeldByPlayer; }
#ifdef CLIENT_DLL
virtual int DrawModel( int flags, const RenderableInstance_t &instance ) OVERRIDE;
#endif
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
bool IsThrownUnderhand( void ) { return (m_flThrowStrength <= GRENADE_UNDERHAND_THRESHOLD); }
float GetThrownStrength( void ) { return m_flThrowStrength; }
float ApproachThrownStrength( void );
#endif
#ifndef CLIENT_DLL
bool HasEmittedProjectile( void ) const { return m_bHasEmittedProjectile; }
bool m_bHasEmittedProjectile;
#endif
#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, const CCSWeaponInfo& weaponInfo );
#endif
protected:
CNetworkVar( bool, m_bRedraw ); // Draw the weapon again after throwing a grenade
CNetworkVar( bool, m_bIsHeldByPlayer ); // is true when held by player, false when it's been thrown or dropped
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.
CNetworkVar( bool, m_bLoopingSoundPlaying ); // Set to true when the grenade is playing a looping sound
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
CNetworkVar( float, m_flThrowStrength );
#endif
private:
CBaseCSGrenade( const CBaseCSGrenade & ) {}
#ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
float m_flThrowStrengthClientSmooth;
#endif
};
inline bool CBaseCSGrenade::IsPinPulled() const
{
return m_bPinPulled;
}
#endif // WEAPON_BASECSGRENADE_H
+273
View File
@@ -0,0 +1,273 @@
//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============//
//
// Purpose: base class for belt items, eg pills and adrenaline
//
// $NoKeywords: $
//=====================================================================================//
#include "cbase.h"
#include "weapon_baseitem.h"
#include "cs_gamerules.h"
#if defined( CLIENT_DLL )
#include "c_cs_player.h"
#include "HUD/sfweaponselection.h"
#else
#include "cs_player.h"
#endif // CLIENT_DLL
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponBaseItem, DT_WeaponBaseItem )
BEGIN_NETWORK_TABLE( CWeaponBaseItem, DT_WeaponBaseItem )
#ifndef CLIENT_DLL
SendPropBool( SENDINFO( m_bRedraw ) ),
#else
RecvPropBool( RECVINFO( m_bRedraw ) ),
#endif
END_NETWORK_TABLE()
#if defined CLIENT_DLL
BEGIN_PREDICTION_DATA( CWeaponBaseItem )
DEFINE_PRED_FIELD( m_bRedraw, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA()
#endif
#ifndef CLIENT_DLL
BEGIN_DATADESC( CWeaponBaseItem )
DEFINE_FIELD( m_bRedraw, FIELD_BOOLEAN ),
END_DATADESC()
#endif
CWeaponBaseItem::CWeaponBaseItem()
{
m_bRedraw = false;
}
//--------------------------------------------------------------------------------------------------------
void CWeaponBaseItem::Spawn( void )
{
m_UseTimer.Invalidate();
BaseClass::Spawn();
SetCollisionGroup( COLLISION_GROUP_WEAPON );
}
//--------------------------------------------------------------------------------------------------------
bool CWeaponBaseItem::Deploy( void )
{
m_bRedraw = false;
m_UseTimer.Invalidate();
return BaseClass::Deploy();
}
//--------------------------------------------------------------------------------------------------------
bool CWeaponBaseItem::Holster( CBaseCombatWeapon *pSwitchingTo )
{
m_bRedraw = false;
m_UseTimer.Invalidate();
return BaseClass::Holster( pSwitchingTo );
}
//--------------------------------------------------------------------------------------------------
// bool CWeaponBaseItem::CanExtendHelpingHand( void ) const
// {
// return !m_UseTimer.HasStarted() && BaseClass::CanExtendHelpingHand();
// }
//--------------------------------------------------------------------------------------------------------
void CWeaponBaseItem::PrimaryAttack( void )
{
CCSPlayer *pPlayer = ToCSPlayer( GetPlayerOwner() );
if (pPlayer == NULL)
return;
if ( m_UseTimer.HasStarted() )
{
return;
}
// if ( HelpingHandPrimaryAttack() )
// {
// return;
// }
if ( !CanUseOnSelf( pPlayer ) )
return;
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_PRIMARY );
OnStartUse( pPlayer );
m_UseTimer.Start( GetUseTimerDuration() );
}
float CWeaponBaseItem::GetUseTimerDuration( void )
{
return SequenceDuration();
}
extern ConVar z_use_belt_item_tolerance;
//--------------------------------------------------------------------------------------------------------
void CWeaponBaseItem::SecondaryAttack( void )
{
CCSPlayer *pPlayer = ToCSPlayer( GetPlayerOwner() );
if (pPlayer == NULL)
return;
if ( m_UseTimer.HasStarted() )
return;
// static const float GiveRange = 256.0f;
// CCSPlayer *target = ToCSPlayer( pPlayer->FindUseEntity( GiveRange, 0.0f, z_use_belt_item_tolerance.GetFloat(), NULL, true ) ); // Prefer to hit players
// if ( target && target->IsOnASurvivorTeam() && !target->IsIncapacitated() )
// {
// #ifdef GAME_DLL
// pPlayer->GiveActiveWeapon( target );
// #endif
// return;
// }
BaseClass::SecondaryAttack();
}
//--------------------------------------------------------------------------------------------------------
/**
* Called when no buttons are pressed
*/
void CWeaponBaseItem::WeaponIdle( void )
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CWeaponBaseItem::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;
}
//--------------------------------------------------------------------------------------------------------
/**
* Called each frame by the player PostThink
*/
void CWeaponBaseItem::ItemPostFrame( void )
{
CCSPlayer *pPlayer = ToCSPlayer( GetPlayerOwner() );
if ( !pPlayer )
return;
#ifndef CLIENT_DLL
int buttons = pPlayer->m_nButtons;
#endif
BaseClass::ItemPostFrame();
if ( m_UseTimer.HasStarted() && m_UseTimer.IsElapsed() )
{
// pills can only help you so much
CCSPlayer *pPlayer = ToCSPlayer( GetPlayerOwner() );
if ( !pPlayer || !pPlayer->IsAlive() )
{
m_UseTimer.Invalidate();
return;
}
#ifndef CLIENT_DLL
CompleteUse( pPlayer );
// BaseClass::ItemPostFrame() clears IN_ATTACK2, so we restore it here to prevent the next weapon from bashing immediately
pPlayer->m_nButtons = buttons;
m_bRedraw = true;
#endif
m_UseTimer.Invalidate();
// remove the ammo
pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType );
if ( pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
{
pPlayer->Weapon_Drop( this, NULL, NULL );
#ifndef CLIENT_DLL
UTIL_Remove( this );
#endif
}
else
{
pPlayer->SwitchToNextBestWeapon( this );
}
#if defined (CLIENT_DLL)
// when an item is removed, force the local player to update their inventory screen
C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
if ( pLocalPlayer && pLocalPlayer == pPlayer )
{
SFWeaponSelection *pHudWS = GET_HUDELEMENT( SFWeaponSelection );
if ( pHudWS )
{
int nAmmoCount = pPlayer->GetAmmoCount( m_iPrimaryAmmoType );
if ( nAmmoCount <= 0 )
{
pHudWS->ShowAndUpdateSelection( WEPSELECT_DROP, this );
}
else
{
// we need to tell the hud that this weapon still exists and then update the selected weapon
pHudWS->ShowAndUpdateSelection( WEPSELECT_PICKUP, this );
}
}
}
#endif
}
}
// //--------------------------------------------------------------------------------------------------------
// bool CWeaponBaseItem::OnHit( trace_t &trace, const Vector &swingVector, bool firstTime )
// {
// if ( trace.m_pEnt && trace.m_pEnt->IsPlayer() && IsASurvivorTeam( trace.m_pEnt->GetTeamNumber() ) )
// return false; // don't hit survivors who are outside of heal range if we're trying to get close and heal them.
//
// return BaseClass::OnHit( trace, swingVector, firstTime );
// }
//--------------------------------------------------------------------------------------------------------
bool CWeaponBaseItem::SendWeaponAnim( int iActivity )
{
//iActivity = TranslateViewmodelActivity( (Activity)iActivity );
return BaseClass::SendWeaponAnim( iActivity );
}
//--------------------------------------------------------------------------------------------------------
bool CWeaponBaseItem::CanFidget( void )
{
return false;
}
//--------------------------------------------------------------------------------------------------------

Some files were not shown because too many files have changed in this diff Show More