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