Merge branch 'master' into terencehill/menu_hudskin_selector
[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 "../../client/defs.qh"
6         #include "../stats.qh"
7         #include "../util.qh"
8         #include "movetypes.qh"
9         #include "../../lib/csqcmodel/common.qh"
10         #include "../../server/t_items.qh"
11 #elif defined(MENUQC)
12 #elif defined(SVQC)
13         #include "../../server/autocvars.qh"
14 #endif
15
16 void _Movetype_WallFriction(entity this, vector stepnormal)  // SV_WallFriction
17 {
18         /*float d, i;
19         vector into, side;
20         makevectors(this.v_angle);
21         d = (stepnormal * v_forward) + 0.5;
22
23         if(d < 0)
24         {
25             i = (stepnormal * this.move_velocity);
26             into = i * stepnormal;
27             side = this.move_velocity - into;
28             this.move_velocity_x = side.x * (1 * d);
29             this.move_velocity_y = side.y * (1 * d);
30         }*/
31 }
32
33 vector planes[MAX_CLIP_PLANES];
34 int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnormal, float stepheight) // SV_FlyMove
35 {
36         int blocked = 0, bumpcount;
37         int i, j, numplanes = 0;
38         float time_left = dt, grav = 0;
39         vector push;
40         vector primal_velocity, original_velocity, restore_velocity;
41
42         for(i = 0; i < MAX_CLIP_PLANES; ++i)
43                 planes[i] = '0 0 0';
44
45         if(applygravity)
46         {
47                 this.move_didgravity = 1;
48                 grav = dt * (PHYS_ENTGRAVITY(this) ? PHYS_ENTGRAVITY(this) : 1) * PHYS_GRAVITY(this);
49
50                 if(!GAMEPLAYFIX_NOGRAVITYONGROUND || !(this.move_flags & FL_ONGROUND))
51                 {
52                         if(GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
53                                 this.move_velocity_z -= grav * 0.5;
54                         else
55                                 this.move_velocity_z -= grav;
56                 }
57         }
58
59         original_velocity = primal_velocity = restore_velocity = this.move_velocity;
60
61         for(bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++)
62         {
63                 if(this.move_velocity == '0 0 0')
64                         break;
65
66                 push = this.move_velocity * time_left;
67                 _Movetype_PushEntity(this, push, true);
68                 if(trace_startsolid)
69                 {
70                         // we got teleported by a touch function
71                         // let's abort the move
72                         blocked |= 8;
73                         break;
74                 }
75
76                 // this code is used by MOVETYPE_WALK and MOVETYPE_STEP and SV_UnstickEntity
77                 // abort move if we're stuck in the world (and didn't make it out)
78                 if(trace_startsolid && trace_allsolid)
79                 {
80                         this.move_velocity = restore_velocity;
81                         return 3;
82                 }
83
84                 if(trace_fraction == 1)
85                         break;
86
87                 float my_trace_fraction = trace_fraction;
88                 vector my_trace_plane_normal = trace_plane_normal;
89
90                 if(trace_plane_normal.z)
91                 {
92                         if(trace_plane_normal.z > 0.7)
93                         {
94                                 // floor
95                                 blocked |= 1;
96
97                                 if(!trace_ent)
98                                 {
99                                         //dprint("_Movetype_FlyMove: !trace_ent\n");
100                                         trace_ent = world;
101                                 }
102
103                                 this.move_flags |= FL_ONGROUND;
104                                 this.move_groundentity = trace_ent;
105                         }
106                 }
107                 else if(stepheight)
108                 {
109                         // step - handle it immediately
110                         vector org = this.move_origin;
111                         vector steppush = '0 0 1' * stepheight;
112
113                         _Movetype_PushEntity(this, steppush, true);
114                         if(trace_startsolid)
115                         {
116                                 blocked |= 8;
117                                 break;
118                         }
119                         _Movetype_PushEntity(this, push, true);
120                         if(trace_startsolid)
121                         {
122                                 blocked |= 8;
123                                 break;
124                         }
125                         float trace2_fraction = trace_fraction;
126                         steppush = '0 0 1' * (org_z - this.move_origin_z);
127                         _Movetype_PushEntity(this, steppush, true);
128                         if(trace_startsolid)
129                         {
130                                 blocked |= 8;
131                                 break;
132                         }
133
134                         // accept the new position if it made some progress...
135                         if(fabs(this.move_origin_x - org_x) >= 0.03125 || fabs(this.move_origin_y - org_y) >= 0.03125)
136                         {
137                                 trace_endpos = this.move_origin;
138                                 time_left *= 1 - trace2_fraction;
139                                 numplanes = 0;
140                                 continue;
141                         }
142                         else
143                                 this.move_origin = org;
144                 }
145                 else
146                 {
147                         // step - return it to caller
148                         blocked |= 2;
149                         // save the trace for player extrafriction
150                         if(stepnormal)
151                                 stepnormal = trace_plane_normal;
152                 }
153
154                 if(my_trace_fraction >= 0.001)
155                 {
156                         // actually covered some distance
157                         original_velocity = this.move_velocity;
158                         numplanes = 0;
159                 }
160
161                 time_left *= 1 - my_trace_fraction;
162
163                 // clipped to another plane
164                 if(numplanes >= MAX_CLIP_PLANES)
165                 {
166                         // this shouldn't really happen
167                         this.move_velocity = '0 0 0';
168                         blocked = 3;
169                         break;
170                 }
171
172                 planes[numplanes] = my_trace_plane_normal;
173                 numplanes++;
174
175                 // modify original_velocity so it parallels all of the clip planes
176                 vector new_velocity = '0 0 0';
177                 for (i = 0;i < numplanes;i++)
178                 {
179                         new_velocity = _Movetype_ClipVelocity(original_velocity, planes[i], 1);
180                         for (j = 0;j < numplanes;j++)
181                         {
182                                 if(j != i)
183                                 {
184                                         // not ok
185                                         if((new_velocity * planes[j]) < 0)
186                                                 break;
187                                 }
188                         }
189                         if(j == numplanes)
190                                 break;
191                 }
192
193                 if(i != numplanes)
194                 {
195                         // go along this plane
196                         this.move_velocity = new_velocity;
197                 }
198                 else
199                 {
200                         // go along the crease
201                         if(numplanes != 2)
202                         {
203                                 this.move_velocity = '0 0 0';
204                                 blocked = 7;
205                                 break;
206                         }
207                         vector dir = cross(planes[0], planes[1]);
208                         // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
209                         float ilength = sqrt((dir * dir));
210                         if(ilength)
211                                 ilength = 1.0 / ilength;
212                         dir.x *= ilength;
213                         dir.y *= ilength;
214                         dir.z *= ilength;
215                         float d = (dir * this.move_velocity);
216                         this.move_velocity = dir * d;
217                 }
218
219                 // if current velocity is against the original velocity,
220                 // stop dead to avoid tiny occilations in sloping corners
221                 if((this.move_velocity * primal_velocity) <= 0)
222                 {
223                         this.move_velocity = '0 0 0';
224                         break;
225                 }
226         }
227
228         // LordHavoc: this came from QW and allows you to get out of water more easily
229         if(GAMEPLAYFIX_EASIERWATERJUMP && (this.move_flags & FL_WATERJUMP) && !(blocked & 8))
230                 this.move_velocity = primal_velocity;
231
232         if(applygravity)
233         {
234                 if(!GAMEPLAYFIX_NOGRAVITYONGROUND || !(this.move_flags & FL_ONGROUND))
235                 {
236                         if(GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
237                                 this.move_velocity_z -= grav * 0.5f;
238                 }
239         }
240
241         return blocked;
242 }
243
244 void _Movetype_CheckVelocity(entity this)  // SV_CheckVelocity
245 {
246         // if(vlen(this.move_velocity) < 0.0001)
247         // this.move_velocity = '0 0 0';
248 }
249
250 bool _Movetype_CheckWater(entity this)  // SV_CheckWater
251 {
252         vector point = this.move_origin;
253         point.z += this.mins.z + 1;
254
255         int nativecontents = pointcontents(point);
256         if(this.move_watertype && this.move_watertype != nativecontents)
257         {
258                 // dprintf("_Movetype_CheckWater(): Original: '%d', New: '%d'\n", this.move_watertype, nativecontents);
259                 if(this.contentstransition)
260                         this.contentstransition(this.move_watertype, nativecontents);
261         }
262
263         this.move_waterlevel = WATERLEVEL_NONE;
264         this.move_watertype = CONTENT_EMPTY;
265
266         int supercontents = Mod_Q1BSP_SuperContentsFromNativeContents(nativecontents);
267         if(supercontents & DPCONTENTS_LIQUIDSMASK)
268         {
269                 this.move_watertype = nativecontents;
270                 this.move_waterlevel = WATERLEVEL_WETFEET;
271                 point.z = this.move_origin.z + (this.mins.z + this.maxs.z) * 0.5;
272                 if(Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(point)) & DPCONTENTS_LIQUIDSMASK)
273                 {
274                         this.move_waterlevel = WATERLEVEL_SWIMMING;
275                         point.z = this.move_origin.z + this.view_ofs.z;
276                         if(Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(point)) & DPCONTENTS_LIQUIDSMASK)
277                                 this.move_waterlevel = WATERLEVEL_SUBMERGED;
278                 }
279         }
280
281         return this.move_waterlevel > 1;
282 }
283
284 void _Movetype_CheckWaterTransition(entity ent)  // SV_CheckWaterTransition
285 {
286         int contents = pointcontents(ent.move_origin);
287
288         if(!ent.move_watertype)
289         {
290                 // just spawned here
291                 if(!autocvar_cl_gameplayfix_fixedcheckwatertransition)
292                 {
293                         ent.move_watertype = contents;
294                         ent.move_waterlevel = 1;
295                         return;
296                 }
297         }
298         else if(ent.move_watertype != contents)
299         {
300                 // dprintf("_Movetype_CheckWaterTransition(): Origin: %s, Direct: '%d', Original: '%d', New: '%d'\n", vtos(ent.move_origin), pointcontents(ent.move_origin), ent.move_watertype, contents);
301                 if(ent.contentstransition)
302                         ent.contentstransition(ent.move_watertype, contents);
303         }
304
305         if(contents <= CONTENT_WATER)
306         {
307                 ent.move_watertype = contents;
308                 ent.move_waterlevel = 1;
309         }
310         else
311         {
312                 ent.move_watertype = CONTENT_EMPTY;
313                 ent.move_waterlevel = (autocvar_cl_gameplayfix_fixedcheckwatertransition ? 0 : contents);
314         }
315 }
316
317 void _Movetype_Impact(entity this, entity oth)  // SV_Impact
318 {
319         entity oldother = other;
320
321         if(this.move_touch)
322         {
323                 other = oth;
324
325                 WITH(entity, self, this, this.move_touch());
326
327                 other = oldother;
328         }
329
330         if(oth.move_touch)
331         {
332                 other = this;
333
334                 WITH(entity, self, oth, oth.move_touch());
335
336                 other = oldother;
337         }
338 }
339
340 void _Movetype_LinkEdict_TouchAreaGrid(entity this)  // SV_LinkEdict_TouchAreaGrid
341 {
342         entity oldother = other;
343
344         for (entity e = findradius(0.5 * (this.absmin + this.absmax), 0.5 * vlen(this.absmax - this.absmin)); e; e = e.chain)
345         {
346                 if(e.move_nomonsters != MOVE_NOMONSTERS && e.move_nomonsters != MOVE_WORLDONLY)
347                 if(e.move_touch && boxesoverlap(e.absmin, e.absmax, this.absmin, this.absmax))
348                 {
349                         other = this;
350
351                         trace_allsolid = false;
352                         trace_startsolid = false;
353                         trace_fraction = 1;
354                         trace_inwater = false;
355                         trace_inopen = true;
356                         trace_endpos = e.move_origin;
357                         trace_plane_normal = '0 0 1';
358                         trace_plane_dist = 0;
359                         trace_ent = this;
360
361                         WITH(entity, self, e, e.move_touch());
362                 }
363         }
364
365         other = oldother;
366 }
367
368 void _Movetype_LinkEdict(entity this, bool touch_triggers)  // SV_LinkEdict
369 {
370         vector mi, ma;
371         if(this.solid == SOLID_BSP)
372         {
373                 // TODO set the absolute bbox
374                 mi = this.mins;
375                 ma = this.maxs;
376         }
377         else
378         {
379                 mi = this.mins;
380                 ma = this.maxs;
381         }
382         mi += this.move_origin;
383         ma += this.move_origin;
384
385         if(this.move_flags & FL_ITEM)
386         {
387                 mi.x -= 15;
388                 mi.y -= 15;
389                 mi.z -= 1;
390                 ma.x += 15;
391                 ma.y += 15;
392                 ma.z += 1;
393         }
394         else
395         {
396                 mi.x -= 1;
397                 mi.y -= 1;
398                 mi.z -= 1;
399                 ma.x += 1;
400                 ma.y += 1;
401                 ma.z += 1;
402         }
403
404         this.absmin = mi;
405         this.absmax = ma;
406
407         if(touch_triggers)
408                 _Movetype_LinkEdict_TouchAreaGrid(this);
409 }
410
411 bool _Movetype_TestEntityPosition(entity this, vector ofs)  // SV_TestEntityPosition
412 {
413 //      vector org = this.move_origin + ofs;
414
415         int cont = this.dphitcontentsmask;
416         this.dphitcontentsmask = DPCONTENTS_SOLID;
417         tracebox(this.move_origin, this.mins, this.maxs, this.move_origin, ((this.move_movetype == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), this);
418         this.dphitcontentsmask = cont;
419
420         if(trace_startsolid)
421                 return true;
422
423         if(vlen(trace_endpos - this.move_origin) > 0.0001)
424                 this.move_origin = trace_endpos;
425         return false;
426 }
427
428 bool _Movetype_UnstickEntity(entity this)  // SV_UnstickEntity
429 {
430         if(!_Movetype_TestEntityPosition(this, '0 0 0')) return true;
431         if(!_Movetype_TestEntityPosition(this, '-1 0 0')) goto success;
432         if(!_Movetype_TestEntityPosition(this, '1 0 0')) goto success;
433         if(!_Movetype_TestEntityPosition(this, '0 -1 0')) goto success;
434         if(!_Movetype_TestEntityPosition(this, '0 1 0')) goto success;
435         if(!_Movetype_TestEntityPosition(this, '-1 -1 0')) goto success;
436         if(!_Movetype_TestEntityPosition(this, '1 -1 0')) goto success;
437         if(!_Movetype_TestEntityPosition(this, '-1 1 0')) goto success;
438         if(!_Movetype_TestEntityPosition(this, '1 1 0')) goto success;
439         for (int i = 1; i <= 17; ++i)
440         {
441                 if(!_Movetype_TestEntityPosition(this, '0 0 -1' * i)) goto success;
442                 if(!_Movetype_TestEntityPosition(this, '0 0 1' * i)) goto success;
443         }
444         LOG_DEBUG("Can't unstick an entity (edict: %d, classname: %s, origin: %s)\n",
445                 num_for_edict(this), this.classname, vtos(this.move_origin));
446         return false;
447         : success;
448         LOG_DEBUG("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)\n",
449                 num_for_edict(this), this.classname, vtos(this.move_origin));
450         _Movetype_LinkEdict(this, true);
451         return true;
452 }
453
454 vector _Movetype_ClipVelocity(vector vel, vector norm, float f)  // SV_ClipVelocity
455 {
456         vel -= ((vel * norm) * norm) * f;
457
458         if(vel.x > -0.1 && vel.x < 0.1) vel.x = 0;
459         if(vel.y > -0.1 && vel.y < 0.1) vel.y = 0;
460         if(vel.z > -0.1 && vel.z < 0.1) vel.z = 0;
461
462         return vel;
463 }
464
465 void _Movetype_PushEntityTrace(entity this, vector push)
466 {
467         vector end = this.move_origin + push;
468         int type;
469         if(this.move_nomonsters)
470                 type = max(0, this.move_nomonsters);
471         else if(this.move_movetype == MOVETYPE_FLYMISSILE)
472                 type = MOVE_MISSILE;
473         else if(this.move_movetype == MOVETYPE_FLY_WORLDONLY)
474                 type = MOVE_WORLDONLY;
475         else if(this.solid == SOLID_TRIGGER || this.solid == SOLID_NOT)
476                 type = MOVE_NOMONSTERS;
477         else
478                 type = MOVE_NORMAL;
479
480         tracebox(this.move_origin, this.mins, this.maxs, end, type, this);
481 }
482
483 float _Movetype_PushEntity(entity this, vector push, bool failonstartsolid)  // SV_PushEntity
484 {
485         _Movetype_PushEntityTrace(this, push);
486
487         if(trace_startsolid && failonstartsolid)
488                 return trace_fraction;
489
490         this.move_origin = trace_endpos;
491
492         if(trace_fraction < 1)
493                 if(this.solid >= SOLID_TRIGGER && (!(this.move_flags & FL_ONGROUND) || (this.move_groundentity != trace_ent)))
494                         _Movetype_Impact(this, trace_ent);
495
496         return trace_fraction;
497 }
498
499
500 .float ltime;
501 .void() blocked;
502 // matrix version of makevectors, sets v_forward, v_right and v_up
503 void makevectors_matrix(vector myangles)  // AngleVectorsFLU
504 {
505         v_forward = v_right = v_up = '0 0 0';
506
507         float y = myangles.y * (M_PI * 2 / 360);
508         float sy = sin(y);
509         float cy = cos(y);
510         float p = myangles.x * (M_PI * 2 / 360);
511         float sp = sin(p);
512         float cp = cos(p);
513         if(v_forward)
514         {
515                 v_forward.x = cp * cy;
516                 v_forward.y = cp * sy;
517                 v_forward.z = -sp;
518         }
519         if(v_right || v_up)
520         {
521                 if(myangles.z)
522                 {
523                         float r = myangles.z * (M_PI * 2 / 360);
524                         float sr = sin(r);
525                         float cr = cos(r);
526                         if(v_right)
527                         {
528                                 v_right.x = sr * sp * cy + cr * -sy;
529                                 v_right.y = sr * sp * sy + cr * cy;
530                                 v_right.z = sr * cp;
531                         }
532                         if(v_up)
533                         {
534                                 v_up.x = cr * sp * cy + -sr * -sy;
535                                 v_up.y = cr * sp * sy + -sr * cy;
536                                 v_up.z = cr * cp;
537                         }
538                 }
539                 else
540                 {
541                         if(v_right)
542                         {
543                                 v_right.x = -sy;
544                                 v_right.y = cy;
545                                 v_right.z = 0;
546                         }
547                         if(v_up)
548                         {
549                                 v_up.x = sp * cy;
550                                 v_up.y = sp * sy;
551                                 v_up.z = cp;
552                         }
553                 }
554         }
555 }
556
557 void _Movetype_Physics_Frame(entity this, float movedt)
558 {
559         this.move_didgravity = -1;
560         switch (this.move_movetype)
561         {
562                 case MOVETYPE_PUSH:
563                 case MOVETYPE_FAKEPUSH:
564                         _Movetype_Physics_Pusher(this, movedt);
565                         break;
566                 case MOVETYPE_NONE:
567                         break;
568                 case MOVETYPE_FOLLOW:
569                         _Movetype_Physics_Follow(this);
570                         break;
571                 case MOVETYPE_NOCLIP:
572                         _Movetype_CheckWater(this);
573                         this.move_origin = this.move_origin + TICRATE * this.move_velocity;
574                         this.move_angles = this.move_angles + TICRATE * this.move_avelocity;
575                         _Movetype_LinkEdict(this, false);
576                         break;
577                 case MOVETYPE_STEP:
578                         _Movetype_Physics_Step(this, movedt);
579                         break;
580                 case MOVETYPE_WALK:
581                         _Movetype_Physics_Walk(this, movedt);
582                         break;
583                 case MOVETYPE_TOSS:
584                 case MOVETYPE_BOUNCE:
585                 case MOVETYPE_BOUNCEMISSILE:
586                 case MOVETYPE_FLYMISSILE:
587                 case MOVETYPE_FLY:
588                 case MOVETYPE_FLY_WORLDONLY:
589                         _Movetype_Physics_Toss(this, movedt);
590                         break;
591                 case MOVETYPE_PHYSICS:
592                         break;
593         }
594 }
595
596 void _Movetype_Physics_ClientFrame(entity this, float movedt)
597 {
598         this.move_didgravity = -1;
599         switch (this.move_movetype)
600         {
601                 case MOVETYPE_PUSH:
602                 case MOVETYPE_FAKEPUSH:
603                         _Movetype_Physics_Pusher(this, movedt);
604                         break;
605                 case MOVETYPE_NONE:
606                         break;
607                 case MOVETYPE_FOLLOW:
608                         _Movetype_Physics_Follow(this);
609                         break;
610                 case MOVETYPE_NOCLIP:
611                         _Movetype_CheckWater(this);
612                         this.move_origin = this.move_origin + TICRATE * this.move_velocity;
613                         this.move_angles = this.move_angles + TICRATE * this.move_avelocity;
614                         _Movetype_LinkEdict(this, false);
615                         break;
616                 case MOVETYPE_STEP:
617                         _Movetype_Physics_Step(this, movedt);
618                         break;
619                 case MOVETYPE_WALK:
620                 case MOVETYPE_FLY:
621                 case MOVETYPE_FLY_WORLDONLY:
622                         _Movetype_Physics_Walk(this, movedt);
623                         break;
624                 case MOVETYPE_TOSS:
625                 case MOVETYPE_BOUNCE:
626                 case MOVETYPE_BOUNCEMISSILE:
627                 case MOVETYPE_FLYMISSILE:
628                         _Movetype_Physics_Toss(this, movedt);
629                         break;
630                 case MOVETYPE_PHYSICS:
631                         break;
632         }
633 }
634
635 void Movetype_Physics_NoMatchServer(entity this)  // optimized
636 {
637         float movedt = time - this.move_time;
638         this.move_time = time;
639
640         _Movetype_Physics_Frame(this, movedt);
641         if(wasfreed(this))
642                 return;
643
644         this.avelocity = this.move_avelocity;
645         this.velocity = this.move_velocity;
646         this.angles = this.move_angles;
647         setorigin(this, this.move_origin);
648 }
649
650 void Movetype_Physics_MatchServer(entity this, bool sloppy)
651 {
652         Movetype_Physics_MatchTicrate(this, TICRATE, sloppy);
653 }
654
655 void Movetype_Physics_MatchTicrate(entity this, float tr, bool sloppy)  // SV_Physics_Entity
656 {
657         if(tr <= 0)
658         {
659                 Movetype_Physics_NoMatchServer(this);
660                 return;
661         }
662
663         float dt = time - this.move_time;
664
665         int n = max(0, floor(dt / tr));
666         dt -= n * tr;
667         this.move_time += n * tr;
668
669         if(!this.move_didgravity)
670                 this.move_didgravity = ((this.move_movetype == MOVETYPE_BOUNCE || this.move_movetype == MOVETYPE_TOSS) && !(this.move_flags & FL_ONGROUND));
671
672         for (int i = 0; i < n; ++i)
673         {
674                 _Movetype_Physics_Frame(this, tr);
675                 if(wasfreed(this))
676                         return;
677         }
678
679         this.avelocity = this.move_avelocity;
680
681         if(dt > 0 && this.move_movetype != MOVETYPE_NONE && !(this.move_flags & FL_ONGROUND))
682         {
683                 // now continue the move from move_time to time
684                 this.velocity = this.move_velocity;
685
686                 if(this.move_didgravity > 0)
687                 {
688                         this.velocity_z -= (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE ? 0.5 : 1)
689                             * dt
690                             * (this.gravity ? this.gravity : 1)
691                             * PHYS_GRAVITY(this);
692                 }
693
694                 this.angles = this.move_angles + dt * this.avelocity;
695
696                 if(sloppy || this.move_movetype == MOVETYPE_NOCLIP)
697                 {
698                         setorigin(this, this.move_origin + dt * this.velocity);
699                 }
700                 else
701                 {
702                         _Movetype_PushEntityTrace(this, dt * this.velocity);
703                         if(!trace_startsolid)
704                                 setorigin(this, trace_endpos);
705                 }
706
707                 if(this.move_didgravity > 0 && GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
708                         this.velocity_z -= 0.5 * dt * (this.gravity ? this.gravity : 1) * PHYS_GRAVITY(this);
709         }
710         else
711         {
712                 this.velocity = this.move_velocity;
713                 this.angles = this.move_angles;
714                 setorigin(this, this.move_origin);
715         }
716 }