Properly support team field on trigger_multiple
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / antilag.qc
1 #include "antilag.qh"
2 #if defined(CSQC)
3 #elif defined(MENUQC)
4 #elif defined(SVQC)
5     #include <server/defs.qh>
6     #include <common/state.qh>
7     #include <common/vehicles/all.qh>
8     #include "antilag.qh"
9 #endif
10
11 const int ANTILAG_MAX_ORIGINS = 64;
12 .vector antilag_origins[ANTILAG_MAX_ORIGINS];
13 .float antilag_times[ANTILAG_MAX_ORIGINS];
14 .int antilag_index;
15 .vector antilag_saved_origin;
16 .float antilag_takenback;
17
18 .float antilag_debug;
19
20 void antilag_record(entity e, entity store, float t)
21 {
22     if (e.vehicle) {
23         if (e.vehicle.vehicle_flags == VHF_PLAYERSLOT) return;
24         antilag_record(e.vehicle, e.vehicle, t);
25     }
26
27         if (time < store.antilag_times[store.antilag_index]) return;
28         store.antilag_index += 1;
29         if (store.antilag_index >= ANTILAG_MAX_ORIGINS)
30                 store.antilag_index = 0;
31         store.antilag_times[store.antilag_index] = t;
32         store.antilag_origins[store.antilag_index] = e.origin;
33
34         if (store.antilag_debug)
35                 te_spark(antilag_takebackorigin(e, store, t - store.antilag_debug), '0 0 0', 32);
36 }
37
38 // finds the index BEFORE t
39 float antilag_find(entity e, entity store, float t)
40 {
41         for(int i = store.antilag_index; i > 0; --i)
42                 if(store.antilag_times[i] >= t)
43                         if(store.antilag_times[i - 1] < t)
44                                 return i - 1;
45
46         if(store.antilag_times[0] >= t)
47                 if(store.antilag_times[ANTILAG_MAX_ORIGINS - 1] < t)
48                         return ANTILAG_MAX_ORIGINS - 1;
49
50         for(int i = ANTILAG_MAX_ORIGINS - 1; i > store.antilag_index + 1; --i)
51                 if(store.antilag_times[i] >= t)
52                         if(store.antilag_times[i - 1] < t)
53                                 return i - 1;
54
55         // if we get here, t is sandwiched nowhere, so let's assume it's in the present
56         return -1;
57 }
58
59 vector antilag_takebackorigin(entity e, entity store, float t)
60 {
61         int i0 = antilag_find(e, store, t);
62         if (i0 < 0)
63         {
64                 // IN THE PRESENT
65                 if(store.antilag_takenback)
66                         return store.antilag_saved_origin;
67                 else
68                         return e.origin;
69         }
70         int i1 = i0 + 1;
71         if (i1 >= ANTILAG_MAX_ORIGINS)
72                 i1 = 0;
73
74         return lerpv(store.antilag_times[i0], store.antilag_origins[i0], store.antilag_times[i1], store.antilag_origins[i1], t);
75 }
76
77 vector antilag_takebackavgvelocity(entity e, entity store, float t0, float t1)
78 {
79         if (t0 >= t1) return '0 0 0';
80         vector o0 = antilag_takebackorigin(e, store, t0);
81         vector o1 = antilag_takebackorigin(e, store, t1);
82         return (o1 - o0) * (1 / (t1 - t0));
83 }
84
85 void antilag_takeback(entity e, entity store, float t)
86 {
87         if (e.vehicle) {
88             if (e.vehicle.vehicle_flags == VHF_PLAYERSLOT) return;
89                 antilag_takeback(e.vehicle, e.vehicle, t);
90     }
91
92         if (!store.antilag_takenback)
93                 store.antilag_saved_origin = e.origin;
94
95         vector org = antilag_takebackorigin(e, store, t);
96         setorigin(e, org);
97         store.antilag_takenback = true;
98 }
99
100 void antilag_restore(entity e, entity store)
101 {
102         if (e.vehicle) {
103             if (e.vehicle.vehicle_flags == VHF_PLAYERSLOT) return;
104                 antilag_restore(e.vehicle, e.vehicle);
105         }
106
107         if (!store.antilag_takenback) return;
108
109         setorigin(e, store.antilag_saved_origin);
110         store.antilag_takenback = false;
111 }
112
113 void antilag_clear(entity e, entity store)
114 {
115         antilag_restore(e, store);
116         for (int i = 0; i < ANTILAG_MAX_ORIGINS; ++i) {
117                 store.antilag_times[i] = -2342;
118                 store.antilag_origins[i] = e.origin;
119         }
120         store.antilag_index = ANTILAG_MAX_ORIGINS - 1; // next one is 0
121 }
122
123 // TODO: use a single intrusive list across all antilagged entities
124 void antilag_takeback_all(entity ignore, float lag)
125 {
126         FOREACH_CLIENT(IS_PLAYER(it) && it != ignore, antilag_takeback(it, CS(it), time - lag));
127         IL_EACH(g_monsters, it != ignore,
128         {
129                 antilag_takeback(it, it, time - lag);
130         });
131         IL_EACH(g_projectiles, it != ignore && it.classname == "nade",
132         {
133                 antilag_takeback(it, it, time - lag);
134         });
135 }
136
137 void antilag_restore_all(entity ignore)
138 {
139         FOREACH_CLIENT(IS_PLAYER(it) && it != ignore, antilag_restore(it, CS(it)));
140         IL_EACH(g_monsters, it != ignore,
141         {
142                 antilag_restore(it, it);
143         });
144         IL_EACH(g_projectiles, it != ignore && it.classname == "nade",
145         {
146                 antilag_restore(it, it);
147         });
148 }