]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/client/movetypes.qc
Add the most obvious __VA_ARGS__ macro of all.
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / movetypes.qc
1 const float STAT_MOVEFLAGS = 225;
2 const float MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE = 4;
3 #define GRAVITY_UNAFFECTED_BY_TICRATE (getstati(STAT_MOVEFLAGS) & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
4
5 .entity move_groundentity; // FIXME add move_groundnetworkentity?
6 .float move_suspendedinair;
7 .float move_didgravity;
8
9 void _Movetype_CheckVelocity() // SV_CheckVelocity
10 {
11 }
12
13 float _Movetype_CheckWater() // SV_CheckWater
14 {
15         return FALSE;
16 }
17
18 void _Movetype_CheckWaterTransition() // SV_CheckWaterTransition
19 {
20 }
21
22 void _Movetype_Impact(entity oth) // SV_Impact
23 {
24         entity oldother, oldself;
25
26         oldself = self;
27         oldother = other;
28
29         if(self.move_touch)
30         {
31                 other = oth;
32
33                 self.move_touch();
34
35                 other = oldother;
36         }
37
38         if(oth.move_touch)
39         {
40                 other = self;
41                 self = oth;
42
43                 self.move_touch();
44
45                 self = oldself;
46                 other = oldother;
47         }
48 }
49
50 void _Movetype_LinkEdict_TouchAreaGrid() // SV_LinkEdict_TouchAreaGrid
51 {
52         entity e, oldself, oldother;
53
54         oldself = self;
55         oldother = other;
56
57         for(e = findradius(0.5 * (self.absmin + self.absmax), 0.5 * vlen(self.absmax - self.absmin)); e; e = e.chain)
58         {
59                 if(e.move_touch)
60                 if(boxesoverlap(e.absmin, e.absmax, oldself.absmin, oldself.absmax))
61                 {
62                         self = e;
63                         other = oldself;
64
65                         trace_allsolid = FALSE;
66                         trace_startsolid = FALSE;
67                         trace_fraction = 1;
68                         trace_inwater = FALSE;
69                         trace_inopen = TRUE;
70                         trace_endpos = e.origin;
71                         trace_plane_normal = '0 0 1';
72                         trace_plane_dist = 0;
73                         trace_ent = oldself;
74
75                         e.move_touch();
76                 }
77         }
78
79         other = oldother;
80         self = oldself;
81 }
82
83 void _Movetype_LinkEdict(float touch_triggers) // SV_LinkEdict
84 {
85         vector mi, ma;
86         if(self.solid == SOLID_BSP)
87         {
88                 // TODO set the absolute bbox
89                 mi = self.mins;
90                 ma = self.maxs;
91         }
92         else
93         {
94                 mi = self.mins;
95                 ma = self.maxs;
96         }
97         mi = mi + self.origin;
98         ma = ma + self.origin;
99
100         if(self.move_flags & FL_ITEM)
101         {
102                 mi_x -= 15;
103                 mi_y -= 15;
104                 mi_z -= 1;
105                 ma_x += 15;
106                 ma_y += 15;
107                 ma_z += 1;
108         }
109         else
110         {
111                 mi_x -= 1;
112                 mi_y -= 1;
113                 mi_z -= 1;
114                 ma_x += 1;
115                 ma_y += 1;
116                 ma_z += 1;
117         }
118
119         self.absmin = mi;
120         self.absmax = ma;
121
122         if(touch_triggers)
123                 _Movetype_LinkEdict_TouchAreaGrid();
124 }
125
126 float _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition
127 {
128         vector org;
129         float cont;
130         org = self.move_origin + ofs;
131
132         cont = self.dphitcontentsmask;
133         self.dphitcontentsmask = DPCONTENTS_SOLID;
134         tracebox(self.move_origin, self.mins, self.maxs, self.move_origin, MOVE_NOMONSTERS, self);
135         self.dphitcontentsmask = cont;
136
137         if(trace_startsolid)
138                 return TRUE;
139
140         if(vlen(trace_endpos - self.move_origin) > 0.0001)
141                 self.move_origin = trace_endpos;
142         return FALSE;
143 }
144
145 float _Movetype_UnstickEntity() // SV_UnstickEntity
146 {
147         if(!_Movetype_TestEntityPosition('0 0 0'))
148                 return TRUE;
149         if(!_Movetype_TestEntityPosition('-1 0 0')) goto success;
150         if(!_Movetype_TestEntityPosition('1 0 0')) goto success;
151         if(!_Movetype_TestEntityPosition('0 -1 0')) goto success;
152         if(!_Movetype_TestEntityPosition('0 1 0')) goto success;
153         if(!_Movetype_TestEntityPosition('-1 -1 0')) goto success;
154         if(!_Movetype_TestEntityPosition('1 -1 0')) goto success;
155         if(!_Movetype_TestEntityPosition('-1 1 0')) goto success;
156         if(!_Movetype_TestEntityPosition('1 1 0')) goto success;
157         float i;
158         for(i = 1; i <= 17; ++i)
159         {
160                 if(!_Movetype_TestEntityPosition('0 0 -1' * i)) goto success;
161                 if(!_Movetype_TestEntityPosition('0 0 1' * i)) goto success;
162         }
163         dprintf(_("Can't unstick an entity (edict: %d, classname: %s, origin: %s)\n"), num_for_edict(self), self.classname, vtos(self.move_origin));
164         return FALSE;
165 :success
166         dprintf(_("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)\n"), num_for_edict(self), self.classname, vtos(self.move_origin));
167         _Movetype_LinkEdict(TRUE);
168         return TRUE;
169 }
170
171 vector _Movetype_ClipVelocity(vector vel, vector norm, float f) // SV_ClipVelocity
172 {
173         vel = vel - ((vel * norm) * norm) * f;
174
175         if(vel_x > -0.1 && vel_x < 0.1) vel_x = 0;
176         if(vel_y > -0.1 && vel_y < 0.1) vel_y = 0;
177         if(vel_z > -0.1 && vel_z < 0.1) vel_z = 0;
178
179         return vel;
180 }
181
182 void _Movetype_PushEntityTrace(vector push)
183 {
184         vector end;
185         float type;
186
187         end = self.move_origin + push;
188
189         if(self.move_nomonsters)
190                 type = max(0, self.move_nomonsters);
191         else if(self.move_movetype == MOVETYPE_FLYMISSILE)
192                 type = MOVE_MISSILE;
193         else if(self.solid == SOLID_TRIGGER || self.solid == SOLID_NOT)
194                 type = MOVE_NOMONSTERS;
195         else
196                 type = MOVE_NORMAL;
197
198         tracebox(self.move_origin, self.mins, self.maxs, end, type, self);
199 }
200
201 float _Movetype_PushEntity(vector push, float failonstartsolid) // SV_PushEntity
202 {
203         _Movetype_PushEntityTrace(push);
204
205         if(trace_startsolid && failonstartsolid)
206                 return trace_fraction;
207
208         self.move_origin = trace_endpos;
209
210         if(trace_fraction < 1)
211                 if(self.solid >= SOLID_TRIGGER && (!(self.move_flags & FL_ONGROUND) || (self.move_groundentity != trace_ent)))
212                         _Movetype_Impact(trace_ent);
213
214         return trace_fraction;
215 }
216
217 #define MAX_CLIP_PLANES 5
218 void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss
219 {
220         if(self.move_flags & FL_ONGROUND)
221         {
222                 if(self.move_velocity_z >= 1/32)
223                         self.move_flags &= ~FL_ONGROUND;
224                 else if(!self.move_groundentity)
225                         return;
226                 else if(self.move_suspendedinair && wasfreed(self.move_groundentity))
227                 {
228                         self.move_groundentity = world;
229                         return;
230                 }
231         }
232
233         self.move_suspendedinair = FALSE;
234
235         _Movetype_CheckVelocity();
236
237         if(self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS)
238         {
239                 self.move_didgravity = 1;
240                 if(GRAVITY_UNAFFECTED_BY_TICRATE)
241                 {
242                         if(self.gravity)
243                                 self.move_velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
244                         else
245                                 self.move_velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
246                 }
247                 else
248                 {
249                         if(self.gravity)
250                                 self.move_velocity_z -= dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
251                         else
252                                 self.move_velocity_z -= dt * getstatf(STAT_MOVEVARS_GRAVITY);
253                 }
254         }
255
256         self.move_angles = self.move_angles + self.move_avelocity * dt;
257
258         float movetime, bump;
259         movetime = dt;
260         for(bump = 0; bump < MAX_CLIP_PLANES && movetime > 0; ++bump)
261         {
262                 vector move;
263                 move = self.move_velocity * movetime;
264                 _Movetype_PushEntity(move, TRUE);
265                 if(wasfreed(self))
266                         return;
267
268                 if(trace_startsolid)
269                 {
270                         _Movetype_UnstickEntity();
271                         _Movetype_PushEntity(move, FALSE);
272                         if(wasfreed(self))
273                                 return;
274                 }
275
276                 if(trace_fraction == 1)
277                         break;
278
279                 movetime *= 1 - min(1, trace_fraction);
280
281                 if(self.move_movetype == MOVETYPE_BOUNCEMISSILE)
282                 {
283                         self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 2.0);
284                         self.move_flags &= ~FL_ONGROUND;
285                 }
286                 else if(self.move_movetype == MOVETYPE_BOUNCE)
287                 {
288                         float d, bouncefac, bouncestop;
289
290                         bouncefac = self.move_bounce_factor;     if(!bouncefac)  bouncefac = 0.5;
291                         bouncestop = self.move_bounce_stopspeed; if(!bouncestop) bouncestop = 60 / 800;
292                         if(self.gravity)
293                                 bouncestop *= self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
294                         else
295                                 bouncestop *= getstatf(STAT_MOVEVARS_GRAVITY);
296
297                         self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1 + bouncefac);
298
299                         d = trace_plane_normal * self.move_velocity;
300                         if(trace_plane_normal_z > 0.7 && d < bouncestop && d > -bouncestop)
301                         {
302                                 self.move_flags |= FL_ONGROUND;
303                                 self.move_groundentity = trace_ent;
304                                 self.move_velocity = '0 0 0';
305                                 self.move_avelocity = '0 0 0';
306                         }
307                         else
308                                 self.move_flags &= ~FL_ONGROUND;
309                 }
310                 else
311                 {
312                         self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1.0);
313                         if(trace_plane_normal_z > 0.7)
314                         {
315                                 self.move_flags |= FL_ONGROUND;
316                                 self.move_groundentity = trace_ent;
317                                 if(trace_ent.solid == SOLID_BSP)
318                                         self.move_suspendedinair = TRUE;
319                                 self.move_velocity = '0 0 0';
320                                 self.move_avelocity = '0 0 0';
321                         }
322                         else
323                                 self.move_flags &= ~FL_ONGROUND;
324                 }
325
326                 // DP revision 8905 (just, WHY...)
327                 if(self.move_movetype == MOVETYPE_BOUNCEMISSILE)
328                         break;
329
330                 // DP revision 8918 (WHY...)
331                 if(self.move_flags & FL_ONGROUND)
332                         break;
333         }
334
335         if(GRAVITY_UNAFFECTED_BY_TICRATE)
336         if(self.move_didgravity > 0)
337         if(!(self.move_flags & FL_ONGROUND))
338         {
339                 if(self.gravity)
340                         self.move_velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
341                 else
342                         self.move_velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
343         }
344
345         _Movetype_CheckWaterTransition();
346 }
347
348 void _Movetype_Physics_Frame(float movedt)
349 {
350         self.move_didgravity = -1;
351         switch(self.move_movetype)
352         {
353                 case MOVETYPE_PUSH:
354                 case MOVETYPE_FAKEPUSH:
355                         error("SV_Physics_Pusher not implemented");
356                         break;
357                 case MOVETYPE_NONE:
358                         break;
359                 case MOVETYPE_FOLLOW:
360                         error("SV_Physics_Follow not implemented");
361                         break;
362                 case MOVETYPE_NOCLIP:
363                         _Movetype_CheckWater();
364                         self.move_origin = self.move_origin + ticrate * self.move_velocity;
365                         self.move_angles = self.move_angles + ticrate * self.move_avelocity;
366                         _Movetype_LinkEdict(FALSE);
367                         break;
368                 case MOVETYPE_STEP:
369                         error("SV_Physics_Step not implemented");
370                         break;
371                 case MOVETYPE_WALK:
372                         error("SV_Physics_Walk not implemented");
373                         break;
374                 case MOVETYPE_TOSS:
375                 case MOVETYPE_BOUNCE:
376                 case MOVETYPE_BOUNCEMISSILE:
377                 case MOVETYPE_FLYMISSILE:
378                 case MOVETYPE_FLY:
379                         _Movetype_Physics_Toss(movedt);
380                         break;
381         }
382 }
383
384 void Movetype_Physics_NoMatchServer() // optimized
385 {
386         float movedt;
387
388         movedt = time - self.move_time;
389         self.move_time = time;
390
391         _Movetype_Physics_Frame(movedt);
392         if(wasfreed(self))
393                 return;
394
395         self.avelocity = self.move_avelocity;
396         self.velocity = self.move_velocity;
397         self.angles = self.move_angles;
398         setorigin(self, self.move_origin);
399 }
400
401 void Movetype_Physics_MatchServer(float sloppy)
402 {
403         Movetype_Physics_MatchTicrate(ticrate, sloppy);
404 }
405
406 void Movetype_Physics_MatchTicrate(float tr, float sloppy) // SV_Physics_Entity
407 {
408         float n, i, dt, movedt;
409
410         if(tr <= 0)
411         {
412                 Movetype_Physics_NoMatchServer();
413                 return;
414         }
415
416         dt = time - self.move_time;
417
418         movedt = tr;
419         n = max(0, floor(dt / tr));
420         dt -= n * tr;
421         self.move_time += n * tr;
422
423         if(!self.move_didgravity)
424                 self.move_didgravity = ((self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS) && !(self.move_flags & FL_ONGROUND));
425
426         for(i = 0; i < n; ++i)
427         {
428                 _Movetype_Physics_Frame(movedt);
429                 if(wasfreed(self))
430                         return;
431         }
432
433         self.avelocity = self.move_avelocity;
434
435         if(dt > 0 && self.move_movetype != MOVETYPE_NONE && !(self.move_flags & FL_ONGROUND))
436         {
437                 // now continue the move from move_time to time
438                 self.velocity = self.move_velocity;
439
440                 if(self.move_didgravity > 0)
441                 {
442                         if(GRAVITY_UNAFFECTED_BY_TICRATE)
443                         {
444                                 if(self.gravity)
445                                         self.velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
446                                 else
447                                         self.velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
448                         }
449                         else
450                         {
451                                 if(self.gravity)
452                                         self.velocity_z -= dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
453                                 else
454                                         self.velocity_z -= dt * getstatf(STAT_MOVEVARS_GRAVITY);
455                         }
456                 }
457
458                 self.angles = self.move_angles + dt * self.avelocity;
459
460                 if(sloppy || self.movetype == MOVETYPE_NOCLIP)
461                 {
462                         setorigin(self, self.move_origin + dt * self.velocity);
463                 }
464                 else
465                 {
466                         _Movetype_PushEntityTrace(dt * self.velocity);
467                         if(!trace_startsolid)
468                                 setorigin(self, trace_endpos);
469                 }
470
471                 if(self.move_didgravity > 0)
472                 {
473                         if(GRAVITY_UNAFFECTED_BY_TICRATE)
474                         {
475                                 if(self.gravity)
476                                         self.velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
477                                 else
478                                         self.velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
479                         }
480                 }
481         }
482         else
483         {
484                 self.velocity = self.move_velocity;
485                 self.angles = self.move_angles;
486                 setorigin(self, self.move_origin);
487         }
488 }