Xonotic
accuracy.qc File Reference
#include "accuracy.qh"
#include <common/constants.qh>
#include <common/net_linked.qh>
#include <common/teams.qh>
#include <common/util.qh>
#include <common/weapons/_all.qh>
#include <server/client.qh>
#include <server/damage.qh>
#include <server/mutators/_mod.qh>
#include <server/player.qh>
#include <server/world.qh>
+ Include dependency graph for accuracy.qc:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void accuracy_add (entity this, Weapon w, float fired, float hit)
 
int accuracy_byte (float n, float d)
 
bool accuracy_canbegooddamage (entity attacker)
 
void accuracy_free (entity e)
 
void accuracy_init (entity e)
 
bool accuracy_isgooddamage (entity attacker, entity targ)
 
void accuracy_resend (entity e)
 
void accuracy_reset (entity e)
 
bool accuracy_send (entity this, entity to, int sf)
 
 REPLICATE (cvar_cl_accuracy_data_share, bool, "cl_accuracy_data_share")
 
 REPLICATE (cvar_cl_accuracy_data_receive, bool, "cl_accuracy_data_receive")
 

Variables

float fired_time
 

Function Documentation

◆ accuracy_add()

void accuracy_add ( entity  this,
Weapon  w,
float  fired,
float  hit 
)

Definition at line 83 of file accuracy.qc.

References accuracy_byte(), CS(), entity(), FOREACH_CLIENT, IS_INDEPENDENT_PLAYER, IS_SPEC, Weapon::m_id, time, and WEP_FIRST.

Referenced by Fire_AddDamage(), fireBullet_antilag(), FireRailgunBullet(), RadiusDamageForSource(), and W_SetupShot_Dir_ProjectileSize_Range().

84 {
85  if (IS_INDEPENDENT_PLAYER(this)) return;
86  entity a = CS(this).accuracy;
87  if (!a) return;
88  if (!hit && !fired) return;
89  if (w == WEP_Null) return;
90  int wepid = w.m_id;
91  wepid -= WEP_FIRST;
92  int b = accuracy_byte(a.accuracy_hit[wepid], a.accuracy_fired[wepid]);
93  if (hit) a.accuracy_hit [wepid] += hit;
94  if (fired) a.accuracy_fired[wepid] += fired;
95 
96  if (hit && STAT(HIT_TIME, a) != time) { // only run this once per frame
97  a.accuracy_cnt_hit[wepid] += 1;
98  STAT(HIT_TIME, a) = time;
99  }
100 
101  if (fired && a.fired_time != time) { // only run this once per frame
102  a.accuracy_cnt_fired[wepid] += 1;
103  a.fired_time = time;
104  }
105 
106  if (b == accuracy_byte(a.accuracy_hit[wepid], a.accuracy_fired[wepid])) return; // no change
107  int sf = 1 << (wepid % 24);
108  a.SendFlags |= sf;
109  FOREACH_CLIENT(IS_SPEC(it) && it.enemy == this, { CS(it).accuracy.SendFlags |= sf; });
110 }
const int WEP_FIRST
Definition: all.qh:304
#define IS_INDEPENDENT_PLAYER(e)
Definition: client.qh:314
entity() spawn
ClientState CS(Client this)
Definition: state.qh:47
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
int accuracy_byte(float n, float d)
Definition: accuracy.qc:14
#define IS_SPEC(v)
Definition: utils.qh:10
float time
Definition: csprogsdefs.qc:16
int m_id
Definition: weapon.qh:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ accuracy_byte()

int accuracy_byte ( float  n,
float  d 
)

Definition at line 14 of file accuracy.qc.

References rint().

Referenced by accuracy_add(), and accuracy_send().

15 {
16  if (n <= 0) return 0;
17  if (n > d) return 255;
18  return 1 + rint(n * 100.0 / d);
19 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ accuracy_canbegooddamage()

bool accuracy_canbegooddamage ( entity  attacker)

Definition at line 132 of file accuracy.qc.

References IS_CLIENT, REPLICATE(), and warmup_stage.

Referenced by W_SetupShot_Dir_ProjectileSize_Range().

133 {
134  return !warmup_stage && IS_CLIENT(attacker);
135 }
#define IS_CLIENT(v)
Definition: utils.qh:13
bool warmup_stage
Definition: main.qh:103
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ accuracy_free()

void accuracy_free ( entity  e)

Definition at line 53 of file accuracy.qc.

References CS().

Referenced by ClientState_attach(), and ClientState_detach().

54 {
55  delete(CS(e).accuracy);
56 }
ClientState CS(Client this)
Definition: state.qh:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ accuracy_init()

void accuracy_init ( entity  e)

Definition at line 45 of file accuracy.qc.

References accuracy, accuracy_send(), CS(), entity(), and new_pure.

Referenced by ClientState_attach(), and PlayerState_detach().

46 {
47  entity a = CS(e).accuracy = new_pure(accuracy);
48  a.owner = e;
49  a.drawonlytoclient = e;
50  Net_LinkEntity(a, false, 0, accuracy_send);
51 }
entity() spawn
ClientState CS(Client this)
Definition: state.qh:47
bool accuracy_send(entity this, entity to, int sf)
Definition: accuracy.qc:21
entity accuracy
Definition: accuracy.qh:26
#define new_pure(class)
purely logical entities (.origin doesn&#39;t work)
Definition: oo.qh:62
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ accuracy_isgooddamage()

bool accuracy_isgooddamage ( entity  attacker,
entity  targ 
)

Definition at line 112 of file accuracy.qc.

References IS_CLIENT, IS_DEAD, MUT_ACCADD_INVALID, MUT_ACCADD_VALID, MUTATOR_CALLHOOK, SAME_TEAM, time, and warmup_stage.

Referenced by Fire_AddDamage(), fireBullet_antilag(), PlayerDamage(), and RadiusDamageForSource().

113 {
114  int mutator_check = MUTATOR_CALLHOOK(AccuracyTargetValid, attacker, targ);
115 
116  if (warmup_stage || game_stopped) return false;
117 
118  // damage to dead/frozen players is good only if it happens in the frame they get killed / frozen
119  // so that stats for weapons that shoot multiple projectiles per shot are properly counted
120  if (IS_DEAD(targ) && time > targ.death_time) return false;
121  if (STAT(FROZEN, targ) && time > targ.freeze_time) return false;
122  if (SAME_TEAM(attacker, targ)) return false;
123 
124  if (mutator_check == MUT_ACCADD_INVALID) return true;
125 
126  if (mutator_check != MUT_ACCADD_VALID) return false;
127  if (!IS_CLIENT(targ) || !IS_CLIENT(attacker)) return false;
128 
129  return true;
130 }
#define IS_CLIENT(v)
Definition: utils.qh:13
bool warmup_stage
Definition: main.qh:103
#define SAME_TEAM(a, b)
Definition: teams.qh:239
#define IS_DEAD(s)
Definition: utils.qh:26
#define MUTATOR_CALLHOOK(id,...)
Definition: base.qh:140
float time
Definition: csprogsdefs.qc:16
+ Here is the caller graph for this function:

◆ accuracy_resend()

void accuracy_resend ( entity  e)

Definition at line 74 of file accuracy.qc.

References CS().

Referenced by PutObserverInServer(), PutPlayerInServer(), and SpectateSet().

75 {
76  CS(e).accuracy.SendFlags = 0xFFFFFF;
77 }
ClientState CS(Client this)
Definition: state.qh:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ accuracy_reset()

void accuracy_reset ( entity  e)

Definition at line 58 of file accuracy.qc.

References CS(), entity(), and REGISTRY_MAX.

Referenced by reset_map().

59 {
60  entity a = CS(e).accuracy;
61  if (!a) return;
62 
63  for (int i = 0; i < REGISTRY_MAX(Weapons); i++)
64  {
65  a.accuracy_frags[i] = 0;
66  a.accuracy_hit[i] = 0;
67  a.accuracy_fired[i] = 0;
68  a.accuracy_cnt_hit[i] = 0;
69  a.accuracy_cnt_fired[i] = 0;
70  }
71 }
entity() spawn
ClientState CS(Client this)
Definition: state.qh:47
#define REGISTRY_MAX(id)
Definition: registry.qh:17
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ accuracy_send()

bool accuracy_send ( entity  this,
entity  to,
int  sf 
)

Definition at line 21 of file accuracy.qc.

References accuracy_byte(), autocvar_sv_accuracy_data_share, CS(), CS_CVAR, entity(), IS_SPEC, owner, WEP_FIRST, WEP_LAST, and WriteByte().

Referenced by accuracy_init().

22 {
23  WriteHeader(MSG_ENTITY, ENT_CLIENT_ACCURACY);
24 
25  entity a = this.owner;
26  if (IS_SPEC(a)) a = a.enemy;
27  a = CS(a).accuracy;
28 
29  if (to != a.owner)
30  if (!autocvar_sv_accuracy_data_share && !CS_CVAR(a.owner).cvar_cl_accuracy_data_share)
31  sf = 0;
32  // note: zero sendflags can never be sent... so we can use that to say that we send no accuracy!
33  WriteInt24_t(MSG_ENTITY, sf);
34  if (sf == 0) return true;
35  // note: we know that client and server agree about SendFlags...
36  int f = 1;
37  for (int w = 0; w <= WEP_LAST - WEP_FIRST; ++w) {
38  if (sf & f) WriteByte(MSG_ENTITY, accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w]));
39  f = (f == 0x800000) ? 1 : f * 2;
40  }
41  return true;
42 }
const int WEP_FIRST
Definition: all.qh:304
entity() spawn
ClientState CS(Client this)
Definition: state.qh:47
#define CS_CVAR(this)
Definition: state.qh:51
entity to
Definition: self.qh:96
#define WEP_LAST
Definition: all.qh:305
int accuracy_byte(float n, float d)
Definition: accuracy.qc:14
entity owner
Definition: main.qh:73
#define IS_SPEC(v)
Definition: utils.qh:10
float autocvar_sv_accuracy_data_share
Weapon Accuracy stats.
Definition: accuracy.qh:21
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ REPLICATE() [1/2]

REPLICATE ( cvar_cl_accuracy_data_share  ,
bool  ,
"cl_accuracy_data_share"   
)

Referenced by accuracy_canbegooddamage().

+ Here is the caller graph for this function:

◆ REPLICATE() [2/2]

REPLICATE ( cvar_cl_accuracy_data_receive  ,
bool  ,
"cl_accuracy_data_receive"   
)

Variable Documentation

◆ fired_time

float fired_time

Definition at line 81 of file accuracy.qc.