]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/weapons/accuracy.qc
3d97c19e734697c39b436194e77ef17dc93986fe
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / weapons / accuracy.qc
1 #include "accuracy.qh"
2 #include "../_.qh"
3
4 #include "../mutators/mutators_include.qh"
5 #include "../../common/constants.qh"
6 #include "../../common/teams.qh"
7 #include "../../common/util.qh"
8 #include "../../common/weapons/weapons.qh"
9
10 float accuracy_byte(float n, float d)
11 {
12         //printf("accuracy: %d / %d\n", n, d);
13         if(n <= 0)
14                 return 0;
15         if(n > d)
16                 return 255;
17         return 1 + rint(n * 100.0 / d);
18 }
19
20 float accuracy_send(entity to, int sf)
21 {
22         int w, f;
23         entity a;
24         WriteByte(MSG_ENTITY, ENT_CLIENT_ACCURACY);
25
26         a = self.owner;
27         if(IS_SPEC(a))
28                 a = a.enemy;
29         a = a.accuracy;
30
31         if(to != a.owner)
32                 if (!(self.owner.cvar_cl_accuracy_data_share && autocvar_sv_accuracy_data_share))
33                         sf = 0;
34         // note: zero sendflags can never be sent... so we can use that to say that we send no accuracy!
35         WriteInt24_t(MSG_ENTITY, sf);
36         if(sf == 0)
37                 return true;
38         // note: we know that client and server agree about SendFlags...
39         for(w = 0, f = 1; w <= WEP_LAST - WEP_FIRST; ++w)
40         {
41                 if(sf & f)
42                         WriteByte(MSG_ENTITY, accuracy_byte(self.(accuracy_hit[w]), self.(accuracy_fired[w])));
43                 if(f == 0x800000)
44                         f = 1;
45                 else
46                         f *= 2;
47         }
48         return true;
49 }
50
51 // init/free
52 void accuracy_init(entity e)
53 {
54         e.accuracy = spawn();
55         e.accuracy.owner = e;
56         e.accuracy.classname = "accuracy";
57         e.accuracy.drawonlytoclient = e;
58         Net_LinkEntity(e.accuracy, false, 0, accuracy_send);
59 }
60
61 void accuracy_free(entity e)
62 {
63         remove(e.accuracy);
64 }
65
66 // force a resend of a player's accuracy stats
67 void accuracy_resend(entity e)
68 {
69         e.accuracy.SendFlags = 0xFFFFFF;
70 }
71
72 // update accuracy stats
73 .float hit_time;
74 .float fired_time;
75
76 void accuracy_add(entity e, int w, float fired, float hit)
77 {
78         entity a;
79         float b;
80         if(IS_INDEPENDENT_PLAYER(e))
81                 return;
82         a = e.accuracy;
83         if(!a || !(hit || fired))
84                 return;
85         w -= WEP_FIRST;
86         b = accuracy_byte(a.(accuracy_hit[w]), a.(accuracy_fired[w]));
87         if(hit)
88                 a.(accuracy_hit[w]) += hit;
89         if(fired)
90                 a.(accuracy_fired[w]) += fired;
91
92     if(hit && a.hit_time != time) // only run this once per frame
93     {
94         a.(accuracy_cnt_hit[w]) += 1;
95         a.hit_time = time;
96     }
97
98     if(fired && a.fired_time != time) // only run this once per frame
99     {
100         a.(accuracy_cnt_fired[w]) += 1;
101         a.fired_time = time;
102     }
103
104         if(b == accuracy_byte(a.(accuracy_hit[w]), a.(accuracy_fired[w])))
105                 return;
106         w = pow(2, w % 24);
107         a.SendFlags |= w;
108         FOR_EACH_CLIENT(a)
109                 if(IS_SPEC(a))
110                         if(a.enemy == e)
111                                 a.SendFlags |= w;
112 }
113
114 float accuracy_isgooddamage(entity attacker, entity targ)
115 {
116         frag_attacker = attacker;
117         frag_target = targ;
118         float mutator_check = MUTATOR_CALLHOOK(AccuracyTargetValid);
119
120         if(!warmup_stage)
121         if(targ.deadflag == DEAD_NO)
122         if(!targ.frozen)
123         if(mutator_check == MUT_ACCADD_INVALID || (mutator_check == MUT_ACCADD_VALID && IS_CLIENT(targ)))
124         if(DIFF_TEAM(attacker, targ))
125                 return true;
126         return false;
127 }
128
129 float accuracy_canbegooddamage(entity attacker)
130 {
131         if(!warmup_stage)
132                 return true;
133         return false;
134 }