3 #include "../mutators/_all.qh"
4 #include <common/constants.qh>
5 #include <common/teams.qh>
6 #include <common/util.qh>
7 #include <common/weapons/all.qh>
9 int accuracy_byte(float n, float d)
12 if (n > d) return 255;
13 return 1 + rint(n * 100.0 / d);
16 bool accuracy_send(entity this, entity to, int sf)
18 WriteHeader(MSG_ENTITY, ENT_CLIENT_ACCURACY);
20 entity a = this.owner;
21 if (IS_SPEC(a)) a = a.enemy;
25 if (!autocvar_sv_accuracy_data_share && !a.owner.cvar_cl_accuracy_data_share)
27 // note: zero sendflags can never be sent... so we can use that to say that we send no accuracy!
28 WriteInt24_t(MSG_ENTITY, sf);
29 if (sf == 0) return true;
30 // note: we know that client and server agree about SendFlags...
32 for (int w = 0; w <= WEP_LAST - WEP_FIRST; ++w) {
33 if (sf & f) WriteByte(MSG_ENTITY, accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w]));
34 f = (f == 0x800000) ? 1 : f * 2;
40 void accuracy_init(entity e)
42 entity a = e.accuracy = new_pure(accuracy);
44 a.drawonlytoclient = e;
45 Net_LinkEntity(a, false, 0, accuracy_send);
48 void accuracy_free(entity e)
53 // force a resend of a player's accuracy stats
54 void accuracy_resend(entity e)
56 e.accuracy.SendFlags = 0xFFFFFF;
59 // update accuracy stats
63 void accuracy_add(entity this, int w, int fired, int hit)
65 if (IS_INDEPENDENT_PLAYER(this)) return;
66 entity a = this.accuracy;
68 if (!hit && !fired) return;
70 int b = accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w]);
71 if (hit) a.accuracy_hit [w] += hit;
72 if (fired) a.accuracy_fired[w] += fired;
74 if (hit && a.hit_time != time) { // only run this once per frame
75 a.accuracy_cnt_hit[w] += 1;
79 if (fired && a.fired_time != time) { // only run this once per frame
80 a.accuracy_cnt_fired[w] += 1;
84 if (b == accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w])) return; // no change
85 int sf = 1 << (w % 24);
87 FOREACH_CLIENT(IS_SPEC(it) && it.enemy == this, LAMBDA(it.accuracy.SendFlags |= sf));
90 bool accuracy_isgooddamage(entity attacker, entity targ)
92 int mutator_check = MUTATOR_CALLHOOK(AccuracyTargetValid, attacker, targ);
94 if (warmup_stage) return false;
95 if (IS_DEAD(targ)) return false;
96 if (STAT(FROZEN, targ)) return false;
97 if (SAME_TEAM(attacker, targ)) return false;
99 if (mutator_check == MUT_ACCADD_INVALID) return true;
101 if (mutator_check != MUT_ACCADD_VALID) return false;
102 if (!IS_CLIENT(targ)) return false;
107 bool accuracy_canbegooddamage(entity attacker)
109 return !warmup_stage;