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