1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: TF2 Accuracy system
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "player.h"
#include "tf_player.h"
#include "basecombatweapon.h"
#include "vstdlib/random.h"
// THIS ISN'T USED ANYMORE. NO REASON TO MAKE OUR HITSCAN WPNS THIS COMPLEX
// Accuracy is measured as the weapons spread in inches at 1024 units (~85 feet)
// Accuracy is sent to the client, where it's used to generate the size of the accuracy representation.
// Accuracy is a "floating" value, in that it's always moving towards a target accuracy, and takes some time to change
// Accuracy Multipliers
// < 1 increases accuracy, > 1 decreases
#define ACCMULT_DUCKING 0.75 // Player is ducking
#define ACCMULT_RUNNING 1.25 // Player is moving >50% of his max speed
// Ricochet Multiplier
// This works differently to other acc multipliers.
#define ACCMULT_RICOCHET 1.0 // Player is being suppressed by bullet fire
#define ACC_RICOCHET_TIME 1.0 // Amount of time accuracy is affected by a ricochet near the player
#define ACC_RICOCHET_MULTIPLE 0.25 // The effect of ricochets on accuracy is multiplied by this by the number of ricochets nearby
#define ACC_RICOCHET_CAP 10 // Maximum number of bullets to register for suppression fire
#define ACCURACY_CHANGE_SPEED 5
//-----------------------------------------------------------------------------
// Purpose: Calculates the players "accuracy" level
//-----------------------------------------------------------------------------
void CBaseTFPlayer::CalculateAccuracy( void )
{
static flLastTime = 0;
// Get the time since the last calculation
float flTimeSlice = (gpGlobals->curtime - flLastTime);
m_flTargetAccuracy = 0;
if ( !GetPlayerClass() )
return;
// Get the base accuracy from the current weapon
if ( m_hActiveWeapon )
{
m_flTargetAccuracy = m_hActiveWeapon->GetAccuracy();
// Accuracy is increased if the player's crouching
if ( GetFlags() & FL_DUCKING )
m_flTargetAccuracy *= m_hActiveWeapon->GetDuckingMultiplier();
// Accuracy is decreased if the player's moving
if ( m_vecVelocity.Length2D() > ( GetPlayerClass()->GetMaxSpeed() * 0.5 ) )
m_flTargetAccuracy *= m_hActiveWeapon->GetRunningMultiplier();
}
// Accuracy is decreased if the player's arms are injured
// Accuracy is increased if there's an Officer nearby
// Accuracy is decreased if this player's being supressed (bullets/explosions impacting nearby)
float flFarTime = (m_flLastRicochetNearby + ACC_RICOCHET_TIME);
if ( gpGlobals->curtime <= flFarTime )
m_flTargetAccuracy *= 1 + (m_flNumberOfRicochets * ACC_RICOCHET_MULTIPLE) * (ACCMULT_RICOCHET * ((flFarTime - gpGlobals->curtime) / ACC_RICOCHET_TIME));
// Accuracy is decreased if the player's just been hit by a bullet/explosion
// Now float towards the target accuracy
if ( m_bSnapAccuracy )
{
m_bSnapAccuracy = false;
m_flAccuracy = m_flTargetAccuracy;
}
else
{
if ( m_flAccuracy < m_flTargetAccuracy )
{
m_flAccuracy += (flTimeSlice * ACCURACY_CHANGE_SPEED);
if ( m_flAccuracy > m_flTargetAccuracy )
m_flAccuracy = m_flTargetAccuracy ;
}
else if ( m_flAccuracy > m_flTargetAccuracy )
{
m_flAccuracy -= (flTimeSlice * ACCURACY_CHANGE_SPEED);
if ( m_flAccuracy < m_flTargetAccuracy )
m_flAccuracy = m_flTargetAccuracy ;
}
}
// Clip to prevent silly accuracies
if ( m_flAccuracy > 1024 )
m_flAccuracy = 1024;
flLastTime = gpGlobals->curtime;
}
//-----------------------------------------------------------------------------
// Purpose: Snap the players accuracy immediately
//-----------------------------------------------------------------------------
void CBaseTFPlayer::SnapAccuracy( void )
{
m_bSnapAccuracy = true;
}
//-----------------------------------------------------------------------------
// Purpose: Return the player's current accuracy
//-----------------------------------------------------------------------------
float CBaseTFPlayer::GetAccuracy( void )
{
return m_flAccuracy;
}
//-----------------------------------------------------------------------------
// Purpose: Bullets / Explosions are hitting near the player. Reduce his/her accuracy.
//-----------------------------------------------------------------------------
void CBaseTFPlayer::Supress( void )
{
if ( gpGlobals->curtime <= (m_flLastRicochetNearby + ACC_RICOCHET_TIME) )
{
m_flNumberOfRicochets = MIN( ACC_RICOCHET_CAP, m_flNumberOfRicochets + 1 );
}
else
{
m_flNumberOfRicochets = 1;
}
m_flLastRicochetNearby = gpGlobals->curtime;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
Vector CBaseTFPlayer::GenerateFireVector( Vector *viewVector )
{
// Calculate the weapon spread from the player's accuracy
float flAcc = (GetAccuracy() * 0.5) / ACCURACY_DISTANCE;
float flAccuracyAngle = RAD2DEG( atan( flAcc ) );
// If the user passed in a viewVector, use it, otherwise use player's v_angle
Vector angShootAngles = viewVector ? *viewVector : pl->v_angle;
if ( flAccuracyAngle )
{
float x, y, z;
do {
x = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5);
y = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5);
z = x*x+y*y;
} while (z > 1);
angShootAngles.x = UTIL_AngleMod( angShootAngles.x + (x * flAccuracyAngle) );
angShootAngles.y = UTIL_AngleMod( angShootAngles.y + (y * flAccuracyAngle) );
}
Vector forward;
AngleVectors( angShootAngles, &forward );
return forward;
}
|