]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/weapons/accuracy.qc
Merge branch 'Mario/showspecs' into 'master'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / weapons / accuracy.qc
1 #include "accuracy.qh"
2
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>
8
9 int accuracy_byte(float n, float d)
10 {
11         if (n <= 0) return 0;
12         if (n > d) return 255;
13         return 1 + rint(n * 100.0 / d);
14 }
15
16 bool accuracy_send(entity this, entity to, int sf)
17 {
18         WriteHeader(MSG_ENTITY, ENT_CLIENT_ACCURACY);
19
20         entity a = this.owner;
21         if (IS_SPEC(a)) a = a.enemy;
22         a = a.accuracy;
23
24         if (to != a.owner)
25                 if (!autocvar_sv_accuracy_data_share && !a.owner.cvar_cl_accuracy_data_share)
26                         sf = 0;
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...
31         int f = 1;
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;
35         }
36         return true;
37 }
38
39 // init/free
40 void accuracy_init(entity e)
41 {
42         entity a = e.accuracy = new_pure(accuracy);
43         a.owner = e;
44         a.drawonlytoclient = e;
45         Net_LinkEntity(a, false, 0, accuracy_send);
46 }
47
48 void accuracy_free(entity e)
49 {
50         delete(e.accuracy);
51 }
52
53 // force a resend of a player's accuracy stats
54 void accuracy_resend(entity e)
55 {
56         e.accuracy.SendFlags = 0xFFFFFF;
57 }
58
59 // update accuracy stats
60 //.float hit_time;
61 .float fired_time;
62
63 void accuracy_add(entity this, int w, int fired, int hit)
64 {
65         if (IS_INDEPENDENT_PLAYER(this)) return;
66         entity a = this.accuracy;
67         if (!a) return;
68         if (!hit && !fired) return;
69         w -= WEP_FIRST;
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;
73
74     if (hit && a.hit_time != time) { // only run this once per frame
75         a.accuracy_cnt_hit[w] += 1;
76         a.hit_time = time;
77     }
78
79     if (fired && a.fired_time != time) { // only run this once per frame
80         a.accuracy_cnt_fired[w] += 1;
81         a.fired_time = time;
82     }
83
84         if (b == accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w])) return; // no change
85         int sf = 1 << (w % 24);
86         a.SendFlags |= sf;
87         FOREACH_CLIENT(IS_SPEC(it) && it.enemy == this, LAMBDA(it.accuracy.SendFlags |= sf));
88 }
89
90 bool accuracy_isgooddamage(entity attacker, entity targ)
91 {
92         int mutator_check = MUTATOR_CALLHOOK(AccuracyTargetValid, attacker, targ);
93
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;
98
99         if (mutator_check == MUT_ACCADD_INVALID) return true;
100
101         if (mutator_check != MUT_ACCADD_VALID) return false;
102         if (!IS_CLIENT(targ)) return false;
103
104         return true;
105 }
106
107 bool accuracy_canbegooddamage(entity attacker)
108 {
109         return !warmup_stage;
110 }