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