Xonotic
movetypes.qc
Go to the documentation of this file.
1 #include "movetypes.qh"
2 
3 #ifdef SVQC
4 void set_movetype(entity this, int mt)
5 {
6  this.move_movetype = mt;
7  if (mt == MOVETYPE_PHYSICS) {
8  this.move_qcphysics = false;
9  } else if (autocvar_sv_qcphysics == 2) {
10  this.move_qcphysics = true;
11  }
12  if(!IL_CONTAINS(g_moveables, this))
13  IL_PUSH(g_moveables, this); // add it to the moveable entities list (even if it doesn't move!) logic: if an object never sets its movetype, we assume it never does anything notable
14  this.movetype = (this.move_qcphysics) ? MOVETYPE_QCENTITY : mt;
15 }
16 #elif defined(CSQC)
17 void set_movetype(entity this, int mt)
18 {
19  this.move_movetype = mt;
20 }
21 #endif
22 
23 bool _Movetype_NudgeOutOfSolid_PivotIsKnownGood(entity this, vector pivot) // SV_NudgeOutOfSolid_PivotIsKnownGood
24 {
25  vector stuckorigin = this.origin;
26  vector goodmins = pivot, goodmaxs = pivot;
27  for(int bump = 0; bump < 6; bump++)
28  {
29  int coord = 2 - (bump >> 1);
30  int dir = (bump & 1);
31 
32  for(int subbump = 0; ; ++subbump)
33  {
34  vector testorigin = stuckorigin;
35  if(dir)
36  {
37  // pushing maxs
38  switch(coord)
39  {
40  case 0: testorigin.x += this.maxs_x - goodmaxs.x; break;
41  case 1: testorigin.y += this.maxs_y - goodmaxs.y; break;
42  case 2: testorigin.z += this.maxs_z - goodmaxs.z; break;
43  }
44  }
45  else
46  {
47  // pushing mins
48  switch(coord)
49  {
50  case 0: testorigin.x += this.mins_x - goodmins.x; break;
51  case 1: testorigin.y += this.mins_y - goodmins.y; break;
52  case 2: testorigin.z += this.mins_z - goodmins.z; break;
53  }
54  }
55 
56  tracebox(stuckorigin, goodmins, goodmaxs, testorigin, MOVE_NOMONSTERS, this);
57  if(trace_startsolid && trace_ent.solid == SOLID_BSP) // NOTE: this checks for bmodelstartsolid in the engine
58  {
59  // BAD BAD, can't fix that
60  return false;
61  }
62 
63  if(trace_fraction >= 1)
64  break; // it WORKS!
65 
66  if(subbump >= 10)
67  {
68  // BAD BAD, can't fix that
69  return false;
70  }
71 
72  // we hit something... let's move out of it
73  vector move = trace_endpos - testorigin;
74  float nudge = (trace_plane_normal * move) + 0.03125; // FIXME cvar this constant
75  stuckorigin = stuckorigin + nudge * trace_plane_normal;
76  }
77 
78  if(dir)
79  {
80  // pushing maxs
81  switch(coord)
82  {
83  case 0: goodmaxs.x = this.maxs_x; break;
84  case 1: goodmaxs.y = this.maxs_y; break;
85  case 2: goodmaxs.z = this.maxs_z; break;
86  }
87  }
88  else
89  {
90  // pushing mins
91  switch(coord)
92  {
93  case 0: goodmins.x = this.mins_x; break;
94  case 1: goodmins.y = this.mins_y; break;
95  case 2: goodmins.z = this.mins_z; break;
96  }
97  }
98  }
99 
100  // WE WIN
101  this.origin = stuckorigin;
102 
103  return true;
104 }
105 
106 void _Movetype_WallFriction(entity this, vector stepnormal) // SV_WallFriction
107 {
108  /*float d, i;
109  vector into, side;
110  makevectors(this.v_angle);
111  d = (stepnormal * v_forward) + 0.5;
112 
113  if(d < 0)
114  {
115  i = (stepnormal * this.velocity);
116  into = i * stepnormal;
117  side = this.velocity - into;
118  this.velocity_x = side.x * (1 * d);
119  this.velocity_y = side.y * (1 * d);
120  }*/
121 }
122 
124 int _Movetype_FlyMove(entity this, float dt, bool applygravity, bool applystepnormal, float stepheight) // SV_FlyMove
125 {
126  move_stepnormal = '0 0 0';
127 
128  if(dt <= 0)
129  return 0;
130 
131  int blockedflag = 0;
132  int i, j, numplanes = 0;
133  float time_left = dt, grav = 0;
134  vector push;
135  vector primal_velocity, original_velocity;
136  vector restore_velocity = this.velocity;
137 
138  for(i = 0; i < MAX_CLIP_PLANES; ++i)
139  planes[i] = '0 0 0';
140 
141  if(applygravity)
142  {
143  this.move_didgravity = 1;
144  grav = dt * (this.gravity ? this.gravity : 1) * PHYS_GRAVITY(this);
145 
146  if(!GAMEPLAYFIX_NOGRAVITYONGROUND || !IS_ONGROUND(this))
147  {
148  if(GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
149  this.velocity_z -= grav * 0.5;
150  else
151  this.velocity_z -= grav;
152  }
153  }
154 
155  original_velocity = primal_velocity = this.velocity;
156 
157  for(int bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++)
158  {
159  if(this.velocity == '0 0 0')
160  break;
161 
162  push = this.velocity * time_left;
163  if(!_Movetype_PushEntity(this, push, true, false))
164  {
165  // we got teleported by a touch function
166  // let's abort the move
167  blockedflag |= 8;
168  break;
169  }
170 
171  // this code is used by MOVETYPE_WALK and MOVETYPE_STEP and SV_UnstickEntity
172  // abort move if we're stuck in the world (and didn't make it out)
174  {
175  this.velocity = restore_velocity;
176  return 3;
177  }
178 
179  if(trace_fraction == 1)
180  break;
181 
182  float my_trace_fraction = trace_fraction;
183  vector my_trace_plane_normal = trace_plane_normal;
184 
185  if(trace_plane_normal.z)
186  {
187  if(trace_plane_normal.z > 0.7)
188  {
189  // floor
190  blockedflag |= 1;
191 
192  if(!trace_ent)
193  {
194  //dprint("_Movetype_FlyMove: !trace_ent\n");
195  trace_ent = NULL;
196  }
197 
198  SET_ONGROUND(this);
199  this.groundentity = trace_ent;
200  }
201  }
202  else if(stepheight)
203  {
204  // step - handle it immediately
205  vector org = this.origin;
206  vector steppush = '0 0 1' * stepheight;
207 
208  if(!_Movetype_PushEntity(this, steppush, true, false))
209  {
210  blockedflag |= 8;
211  break;
212  }
213  if(!_Movetype_PushEntity(this, push, true, false))
214  {
215  blockedflag |= 8;
216  break;
217  }
218  float trace2_fraction = trace_fraction;
219  steppush = vec3(0, 0, org.z - this.origin_z);
220  if(!_Movetype_PushEntity(this, steppush, true, false))
221  {
222  blockedflag |= 8;
223  break;
224  }
225 
226  // accept the new position if it made some progress...
227  if(fabs(this.origin_x - org.x) >= 0.03125 || fabs(this.origin_y - org.y) >= 0.03125)
228  {
229  trace_endpos = this.origin;
230  time_left *= 1 - trace2_fraction;
231  numplanes = 0;
232  continue;
233  }
234  else
235  this.origin = org;
236  }
237  else
238  {
239  // step - return it to caller
240  blockedflag |= 2;
241  // save the trace for player extrafriction
242  if(applystepnormal)
244  }
245 
246  if(my_trace_fraction >= 0.001)
247  {
248  // actually covered some distance
249  original_velocity = this.velocity;
250  numplanes = 0;
251  }
252 
253  time_left *= 1 - my_trace_fraction;
254 
255  // clipped to another plane
256  if(numplanes >= MAX_CLIP_PLANES)
257  {
258  // this shouldn't really happen
259  this.velocity = '0 0 0';
260  blockedflag = 3;
261  break;
262  }
263 
264  planes[numplanes] = my_trace_plane_normal;
265  numplanes++;
266 
267  // modify original_velocity so it parallels all of the clip planes
268  vector new_velocity = '0 0 0';
269  for (i = 0;i < numplanes;i++)
270  {
271  new_velocity = _Movetype_ClipVelocity(original_velocity, planes[i], 1);
272  for (j = 0;j < numplanes;j++)
273  {
274  if(j != i)
275  {
276  // not ok
277  if((new_velocity * planes[j]) < 0)
278  break;
279  }
280  }
281  if(j == numplanes)
282  break;
283  }
284 
285  if(i != numplanes)
286  {
287  // go along this plane
288  this.velocity = new_velocity;
289  }
290  else
291  {
292  // go along the crease
293  if(numplanes != 2)
294  {
295  this.velocity = '0 0 0';
296  blockedflag = 7;
297  break;
298  }
299  vector dir = cross(planes[0], planes[1]);
300  // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
301  float ilength = sqrt((dir * dir));
302  if(ilength)
303  ilength = 1.0 / ilength;
304  dir.x *= ilength;
305  dir.y *= ilength;
306  dir.z *= ilength;
307  float d = (dir * this.velocity);
308  this.velocity = dir * d;
309  }
310 
311  // if current velocity is against the original velocity,
312  // stop dead to avoid tiny occilations in sloping corners
313  if((this.velocity * primal_velocity) <= 0)
314  {
315  this.velocity = '0 0 0';
316  break;
317  }
318  }
319 
320  // LordHavoc: this came from QW and allows you to get out of water more easily
321  if(GAMEPLAYFIX_EASIERWATERJUMP(this) && (this.flags & FL_WATERJUMP) && !(blockedflag & 8))
322  this.velocity = primal_velocity;
323 
324  if(PHYS_WALLCLIP(this) && this.pm_time && !(this.flags & FL_WATERJUMP) && !(blockedflag & 8))
325  this.velocity = primal_velocity;
326 
327  if(applygravity)
328  {
329  if(!GAMEPLAYFIX_NOGRAVITYONGROUND || !IS_ONGROUND(this))
330  {
331  if(GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
332  this.velocity_z -= grav * 0.5f;
333  }
334  }
335 
336  return blockedflag;
337 }
338 
339 void _Movetype_CheckVelocity(entity this) // SV_CheckVelocity
340 {
341  // if(vlen(this.velocity) < 0.0001)
342  // this.velocity = '0 0 0';
343 }
344 
345 bool _Movetype_CheckWater(entity this) // SV_CheckWater
346 {
347  vector point = this.origin;
348  point.z += this.mins.z + 1;
349 
350  int nativecontents = pointcontents(point);
351  if(this.watertype && this.watertype != nativecontents)
352  {
353  // dprintf("_Movetype_CheckWater(): Original: '%d', New: '%d'\n", this.watertype, nativecontents);
354  if(this.contentstransition)
355  this.contentstransition(this.watertype, nativecontents);
356  }
357 
359  this.watertype = CONTENT_EMPTY;
360 
361  int supercontents = Mod_Q1BSP_SuperContentsFromNativeContents(nativecontents);
362  if(supercontents & DPCONTENTS_LIQUIDSMASK)
363  {
364  this.watertype = nativecontents;
366  point.z = this.origin.z + (this.mins.z + this.maxs.z) * 0.5;
367  if(Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(point)) & DPCONTENTS_LIQUIDSMASK)
368  {
370  point.z = this.origin.z + this.view_ofs.z;
371  if(Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(point)) & DPCONTENTS_LIQUIDSMASK)
373  }
374  }
375 
376  return this.waterlevel > 1;
377 }
378 
379 void _Movetype_CheckWaterTransition(entity ent) // SV_CheckWaterTransition
380 {
381  int contents = pointcontents(ent.origin);
382 
383  if(!ent.watertype)
384  {
385  // just spawned here
387  {
388  ent.watertype = contents;
389  ent.waterlevel = 1;
390  return;
391  }
392  }
393  else if(ent.watertype != contents)
394  {
395  // dprintf("_Movetype_CheckWaterTransition(): Origin: %s, Direct: '%d', Original: '%d', New: '%d'\n", vtos(ent.origin), pointcontents(ent.origin), ent.watertype, contents);
396  if(ent.contentstransition)
397  ent.contentstransition(ent.watertype, contents);
398  }
399 
400  if(contents <= CONTENT_WATER)
401  {
402  ent.watertype = contents;
403  ent.waterlevel = 1;
404  }
405  else
406  {
407  ent.watertype = CONTENT_EMPTY;
408  ent.waterlevel = (GAMEPLAYFIX_WATERTRANSITION(ent) ? 0 : contents);
409  }
410 }
411 
412 void _Movetype_Impact(entity this, entity oth) // SV_Impact
413 {
414  if(!this && !oth)
415  return;
416 
417  // due to a lack of pointers in QC, we must save the trace values and restore them for other functions
418  bool save_trace_allsolid = trace_allsolid;
419  bool save_trace_startsolid = trace_startsolid;
420  float save_trace_fraction = trace_fraction;
421  bool save_trace_inwater = trace_inwater;
422  bool save_trace_inopen = trace_inopen;
423  vector save_trace_endpos = trace_endpos;
424  vector save_trace_plane_normal = trace_plane_normal;
425  float save_trace_plane_dist = trace_plane_dist;
426  entity save_trace_ent = trace_ent;
427  int save_trace_dpstartcontents = trace_dpstartcontents;
428  int save_trace_dphitcontents = trace_dphitcontents;
429  int save_trace_dphitq3surfaceflags = trace_dphitq3surfaceflags;
430  string save_trace_dphittexturename = trace_dphittexturename;
431 
432  if(this.solid != SOLID_NOT && gettouch(this))
433  gettouch(this)(this, oth);
434 
435  if(oth.solid != SOLID_NOT && gettouch(oth))
436  gettouch(oth)(oth, this);
437 
438  trace_allsolid = save_trace_allsolid;
439  trace_startsolid = save_trace_startsolid;
440  trace_fraction = save_trace_fraction;
441  trace_inwater = save_trace_inwater;
442  trace_inopen = save_trace_inopen;
443  trace_endpos = save_trace_endpos;
444  trace_plane_normal = save_trace_plane_normal;
445  trace_plane_dist = save_trace_plane_dist;
446  trace_ent = save_trace_ent;
447  trace_dpstartcontents = save_trace_dpstartcontents;
448  trace_dphitcontents = save_trace_dphitcontents;
449  trace_dphitq3surfaceflags = save_trace_dphitq3surfaceflags;
450  trace_dphittexturename = save_trace_dphittexturename;
451 }
452 
453 void _Movetype_LinkEdict_TouchAreaGrid(entity this) // SV_LinkEdict_TouchAreaGrid
454 {
455  if(this.solid == SOLID_NOT)
456  return;
457 
458  // due to a lack of pointers in QC, we must save the trace values and restore them for other functions
459  bool save_trace_allsolid = trace_allsolid;
460  bool save_trace_startsolid = trace_startsolid;
461  float save_trace_fraction = trace_fraction;
462  bool save_trace_inwater = trace_inwater;
463  bool save_trace_inopen = trace_inopen;
464  vector save_trace_endpos = trace_endpos;
465  vector save_trace_plane_normal = trace_plane_normal;
466  float save_trace_plane_dist = trace_plane_dist;
467  entity save_trace_ent = trace_ent;
468  int save_trace_dpstartcontents = trace_dpstartcontents;
469  int save_trace_dphitcontents = trace_dphitcontents;
470  int save_trace_dphitq3surfaceflags = trace_dphitq3surfaceflags;
471  string save_trace_dphittexturename = trace_dphittexturename;
472 
473  FOREACH_ENTITY_RADIUS_ORDERED(0.5 * (this.absmin + this.absmax), 0.5 * vlen(this.absmax - this.absmin), true, {
474  if (it.solid == SOLID_TRIGGER && it != this)
475  if (it.move_nomonsters != MOVE_NOMONSTERS && it.move_nomonsters != MOVE_WORLDONLY)
476  if (gettouch(it) && boxesoverlap(it.absmin, it.absmax, this.absmin, this.absmax))
477  {
478  trace_allsolid = false;
479  trace_startsolid = false;
480  trace_fraction = 1;
481  trace_inwater = false;
482  trace_inopen = true;
483  trace_endpos = it.origin;
484  trace_plane_normal = '0 0 1';
485  trace_plane_dist = 0;
486  trace_ent = this;
487  trace_dpstartcontents = 0;
488  trace_dphitcontents = 0;
489  trace_dphitq3surfaceflags = 0;
490  trace_dphittexturename = string_null;
491 
492  gettouch(it)(it, this);
493  }
494  });
495 
496  trace_allsolid = save_trace_allsolid;
497  trace_startsolid = save_trace_startsolid;
498  trace_fraction = save_trace_fraction;
499  trace_inwater = save_trace_inwater;
500  trace_inopen = save_trace_inopen;
501  trace_endpos = save_trace_endpos;
502  trace_plane_normal = save_trace_plane_normal;
503  trace_plane_dist = save_trace_plane_dist;
504  trace_ent = save_trace_ent;
505  trace_dpstartcontents = save_trace_dpstartcontents;
506  trace_dphitcontents = save_trace_dphitcontents;
507  trace_dphitq3surfaceflags = save_trace_dphitq3surfaceflags;
508  trace_dphittexturename = save_trace_dphittexturename;
509 }
510 
512 void _Movetype_LinkEdict(entity this, bool touch_triggers) // SV_LinkEdict
513 {
514  if(autocvar__movetype_debug)
515  {
516  vector mi, ma;
517  if(this.solid == SOLID_BSP)
518  {
519  // TODO set the absolute bbox
520  mi = this.mins;
521  ma = this.maxs;
522  }
523  else
524  {
525  mi = this.mins;
526  ma = this.maxs;
527  }
528  mi += this.origin;
529  ma += this.origin;
530 
531  if(this.flags & FL_ITEM)
532  {
533  mi -= '15 15 1';
534  ma += '15 15 1';
535  }
536  else
537  {
538  mi -= '1 1 1';
539  ma += '1 1 1';
540  }
541 
542  this.absmin = mi;
543  this.absmax = ma;
544  }
545  else
546  {
547  setorigin(this, this.origin); // calls SV_LinkEdict
548  #ifdef CSQC
549  // NOTE: CSQC's version of setorigin doesn't expand
550  this.absmin -= '1 1 1';
551  this.absmax += '1 1 1';
552  #endif
553  }
554 
555  if(touch_triggers)
557 }
558 
559 int _Movetype_ContentsMask(entity this) // SV_GenericHitSuperContentsMask
560 {
561  if(this)
562  {
563  if(this.dphitcontentsmask)
564  return this.dphitcontentsmask;
565  else if(this.solid == SOLID_SLIDEBOX)
566  {
567  if(this.flags & FL_MONSTER)
569  else
571  }
572  else if(this.solid == SOLID_CORPSE)
574  else if(this.solid == SOLID_TRIGGER)
576  else
578  }
579  else
581 }
582 
584 bool _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition
585 {
587  vector org = this.origin + ofs;
588 
589  //int cont = this.dphitcontentsmask;
590  //this.dphitcontentsmask = DPCONTENTS_SOLID;
591  tracebox(org, this.mins, this.maxs, this.origin, ((this.move_movetype == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), this);
592  //this.dphitcontentsmask = cont;
594  return true;
595 
596  if(vlen2(trace_endpos - this.origin) >= 0.0001)
597  {
598  tracebox(trace_endpos, this.mins, this.maxs, trace_endpos, MOVE_NOMONSTERS, this);
599  if(!trace_startsolid)
600  this.origin = trace_endpos;
601  }
602  return false;
603 }
604 
606 {
607  // NOTE: expects _Movetype_TestEntityPosition_ent to be set to the correct entity
608  // returns true if stuck
609 
610  // start at 2, since the first position has already been checked
611  for(int j = 2; j <= offset; ++j)
612  {
613  if(!_Movetype_TestEntityPosition('0 0 -1' * j))
614  return false;
615  if(!_Movetype_TestEntityPosition('0 0 1' * j))
616  return false;
617  }
618 
619  return true;
620 }
621 
622 int _Movetype_UnstickEntity(entity this) // SV_UnstickEntity
623 {
624  _Movetype_TestEntityPosition_ent = this;
625  if (!_Movetype_TestEntityPosition(' 0 0 0')) {
626  return UNSTICK_FINE;
627  }
628  #define X(v) if (_Movetype_TestEntityPosition(v))
629  X('0 0 -1') X(' 0 0 1')
630  X('-1 0 0') X(' 1 0 0')
631  X(' 0 -1 0') X(' 0 1 0')
632  X('-1 -1 0') X(' 1 -1 0')
633  X('-1 1 0') X(' 1 1 0')
634  #undef X
635  {
636  if(_Movetype_TestEntityPosition_Offset(rint((this.maxs.z - this.mins.z) * 0.36)))
637  {
638  LOG_DEBUGF("Can't unstick an entity (edict: %d, classname: %s, origin: %s)",
639  etof(this), this.classname, vtos(this.origin));
640  return UNSTICK_STUCK;
641  }
642  }
643  LOG_DEBUGF("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)",
644  etof(this), this.classname, vtos(this.origin));
645  _Movetype_LinkEdict(this, false);
646  return UNSTICK_FIXED;
647 }
648 
649 void _Movetype_CheckStuck(entity this) // SV_CheckStuck
650 {
651  int unstick = _Movetype_UnstickEntity(this); // sets test position entity
652  switch(unstick)
653  {
654  case UNSTICK_FINE:
655  this.oldorigin = this.origin;
656  break;
657  case UNSTICK_FIXED:
658  break; // already sorted
659  case UNSTICK_STUCK:
660  vector offset = this.oldorigin - this.origin;
661  if(!_Movetype_TestEntityPosition(offset))
662  _Movetype_LinkEdict(this, false);
663  // couldn't unstick, should we warn about this?
664  break;
665  }
666 }
667 
668 vector _Movetype_ClipVelocity(vector vel, vector norm, float f) // ClipVelocity
669 {
670  vel -= ((vel * norm) * norm) * f;
671 
672  if(vel.x > -0.1 && vel.x < 0.1) vel.x = 0;
673  if(vel.y > -0.1 && vel.y < 0.1) vel.y = 0;
674  if(vel.z > -0.1 && vel.z < 0.1) vel.z = 0;
675 
676  return vel;
677 }
678 
680 {
681  vector end = this.origin + push;
682  int type;
683  if(this.move_nomonsters)
684  type = max(0, this.move_nomonsters);
685  else if(this.move_movetype == MOVETYPE_FLYMISSILE)
686  type = MOVE_MISSILE;
687  else if(this.move_movetype == MOVETYPE_FLY_WORLDONLY)
688  type = MOVE_WORLDONLY;
689  else if(this.solid == SOLID_TRIGGER || this.solid == SOLID_NOT)
690  type = MOVE_NOMONSTERS;
691  else
692  type = MOVE_NORMAL;
693 
694  tracebox(this.origin, this.mins, this.maxs, end, type, this);
695 }
696 
697 bool _Movetype_PushEntity(entity this, vector push, bool failonstartsolid, bool dolink) // SV_PushEntity
698 {
699  _Movetype_PushEntityTrace(this, push);
700 
701  // NOTE: this is a workaround for the QC's lack of a worldstartsolid trace parameter
702  if(trace_startsolid && failonstartsolid)
703  {
704  int oldtype = this.move_nomonsters;
706  _Movetype_PushEntityTrace(this, push);
707  this.move_nomonsters = oldtype;
708  if(trace_startsolid)
709  return true;
710  }
711 
712  this.origin = trace_endpos;
713 
714  vector last_origin = this.origin;
715 
716  _Movetype_LinkEdict(this, dolink);
717 
718  if((this.solid >= SOLID_TRIGGER && trace_fraction < 1 && (!IS_ONGROUND(this) || this.groundentity != trace_ent)))
720 
721  return (this.origin == last_origin); // false if teleported by touch
722 }
723 
724 void _Movetype_Physics_Frame(entity this, float movedt)
725 {
726  this.move_didgravity = -1;
727  switch (this.move_movetype)
728  {
729  case MOVETYPE_PUSH:
730  case MOVETYPE_FAKEPUSH:
731  _Movetype_Physics_Push(this, movedt);
732  break;
733  case MOVETYPE_NONE:
734  break;
735  case MOVETYPE_FOLLOW:
737  break;
738  case MOVETYPE_NOCLIP:
739  _Movetype_CheckWater(this);
740  this.origin = this.origin + movedt * this.velocity;
741  this.angles = this.angles + movedt * this.avelocity;
742  _Movetype_LinkEdict(this, false);
743  break;
744  case MOVETYPE_STEP:
745  _Movetype_Physics_Step(this, movedt);
746  break;
747  case MOVETYPE_WALK:
748  _Movetype_Physics_Walk(this, movedt);
749  break;
750  case MOVETYPE_TOSS:
751  case MOVETYPE_BOUNCE:
753  case MOVETYPE_FLYMISSILE:
754  case MOVETYPE_FLY:
756  _Movetype_Physics_Toss(this, movedt);
757  break;
758  case MOVETYPE_PHYSICS:
759  break;
760  }
761 }
762 
763 void _Movetype_Physics_ClientFrame(entity this, float movedt)
764 {
765  this.move_didgravity = -1;
766  switch (this.move_movetype)
767  {
768  case MOVETYPE_PUSH:
769  case MOVETYPE_FAKEPUSH:
770  LOG_DEBUG("Physics: Lacking QuakeC support for Push movetype, FIX ME by using engine physics!");
771  break;
772  case MOVETYPE_NONE:
773  break;
774  case MOVETYPE_FOLLOW:
776  break;
777  case MOVETYPE_NOCLIP:
778  _Movetype_CheckWater(this);
779  this.origin = this.origin + movedt * this.velocity;
780  this.angles = this.angles + movedt * this.avelocity;
781  break;
782  case MOVETYPE_STEP:
783  if (GAMEPLAYFIX_UNSTICKPLAYERS(this) == 2)
784  _Movetype_CheckStuck(this);
785  _Movetype_Physics_Step(this, movedt);
786  break;
787  case MOVETYPE_WALK:
788  case MOVETYPE_FLY:
790  if (movedt > 0 && GAMEPLAYFIX_UNSTICKPLAYERS(this) == 2)
791  _Movetype_CheckStuck(this);
792  _Movetype_Physics_Walk(this, movedt);
793  break;
794  case MOVETYPE_TOSS:
795  case MOVETYPE_BOUNCE:
797  case MOVETYPE_FLYMISSILE:
798  if (GAMEPLAYFIX_UNSTICKPLAYERS(this) == 2)
799  _Movetype_CheckStuck(this);
800  _Movetype_Physics_Toss(this, movedt);
801  break;
802  case MOVETYPE_PHYSICS:
803  break;
804  }
805 
806  //_Movetype_CheckVelocity(this);
807 
808  _Movetype_LinkEdict(this, true);
809 
810  //_Movetype_CheckVelocity(this);
811 }
812 
813 void Movetype_Physics_NoMatchTicrate(entity this, float movedt, bool isclient) // to be run every move frame
814 {
815  bool didmove = (this.move_time != 0);
816  this.move_time = time;
817 
818  if(isclient)
819  _Movetype_Physics_ClientFrame(this, movedt);
820  else
821  {
822  // this doesn't apply to clients, and only applies to unmatched entities
823  // don't run think/move on newly spawned projectiles as it messes up
824  // movement interpolation and rocket trails, and is inconsistent with
825  // respect to entities spawned in the same frame
826  // (if an ent spawns a higher numbered ent, it moves in the same frame,
827  // but if it spawns a lower numbered ent, it doesn't - this never moves
828  // ents in the first frame regardless)
829  if(!didmove && GAMEPLAYFIX_DELAYPROJECTILES(this) > 0)
830  return;
831  _Movetype_Physics_Frame(this, movedt);
832  }
833  if(wasfreed(this))
834  return;
835 
836  setorigin(this, this.origin);
837 }
838 
839 void Movetype_Physics_NoMatchServer(entity this) // optimized
840 {
841  float movedt = time - this.move_time;
842  this.move_time = time;
843 
844  _Movetype_Physics_Frame(this, movedt);
845  if(wasfreed(this))
846  return;
847 
848  setorigin(this, this.origin);
849 }
850 
851 void Movetype_Physics_MatchServer(entity this, bool sloppy)
852 {
853  Movetype_Physics_MatchTicrate(this, TICRATE, sloppy);
854 }
855 
856 // saved .move_*
857 .vector tic_origin;
858 .vector tic_velocity;
861 .vector tic_angles;
862 
863 // saved .*
869 void Movetype_Physics_MatchTicrate(entity this, float tr, bool sloppy) // SV_Physics_Entity
870 {
871  // this hack exists to contain the physics feature
872  // (so entities can place themselves in the world and not need to update .tic_* themselves)
873 #define X(s) \
874  if(this.(s) != this.tic_saved_##s) \
875  this.tic_##s = this.(s)
876 
877  X(origin);
878  X(velocity);
879  X(flags);
880  X(avelocity);
881  X(angles);
882 #undef X
883 
884  this.flags = this.tic_flags;
885  this.velocity = this.tic_velocity;
886  setorigin(this, this.tic_origin);
887  this.avelocity = this.tic_avelocity;
888  this.angles = this.tic_angles;
889 
890  if(tr <= 0)
891  {
893 
894  this.tic_saved_flags = this.tic_flags = this.flags;
895  this.tic_saved_velocity = this.tic_velocity = this.velocity;
896  this.tic_saved_origin = this.tic_origin = this.origin;
897  this.tic_saved_avelocity = this.tic_avelocity = this.avelocity;
898  this.tic_saved_angles = this.tic_angles = this.angles;
899  return;
900  }
901 
902  float dt = time - this.move_time;
903 
904  int n = bound(0, floor(dt / tr), 32); // limit the number of frames to 32 (CL_MAX_USERCMDS, using DP_SMALLMEMORY value for consideration of QC's limitations)
905  dt -= n * tr;
906  this.move_time += n * tr;
907 
908  if(!this.move_didgravity)
910 
911  for (int j = 0; j < n; ++j)
912  {
913  _Movetype_Physics_Frame(this, tr);
914  if(wasfreed(this))
915  return;
916  }
917 
918  // update the physics fields
919  this.tic_origin = this.origin;
920  this.tic_velocity = this.velocity;
921  this.tic_avelocity = this.avelocity;
922  this.tic_angles = this.angles;
923  this.tic_flags = this.flags;
924 
925  // restore their actual values
926  this.flags = this.tic_saved_flags;
927  this.velocity = this.tic_saved_velocity;
928  setorigin(this, this.tic_saved_origin);
929  //this.avelocity = this.tic_saved_avelocity;
930  this.angles = this.tic_saved_angles;
931 
932  this.avelocity = this.tic_avelocity;
933 
934  if(dt > 0 && this.move_movetype != MOVETYPE_NONE && !(this.tic_flags & FL_ONGROUND))
935  {
936  // now continue the move from move_time to time
937  this.velocity = this.tic_velocity;
938 
939  if(this.move_didgravity > 0)
940  {
941  this.velocity_z -= (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE ? 0.5 : 1)
942  * dt
943  * ((this.gravity) ? this.gravity : 1)
944  * PHYS_GRAVITY(this);
945  }
946 
947  this.angles = this.tic_angles + dt * this.avelocity;
948 
949  if(sloppy || this.move_movetype == MOVETYPE_NOCLIP)
950  {
951  setorigin(this, this.tic_origin + dt * this.velocity);
952  }
953  else
954  {
955  setorigin(this, this.tic_origin);
956  _Movetype_PushEntityTrace(this, dt * this.velocity);
957  if(!trace_startsolid)
958  setorigin(this, trace_endpos);
959  else
960  setorigin(this, this.tic_saved_origin);
961  }
962 
963  if(this.move_didgravity > 0 && GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
964  this.velocity_z -= 0.5 * dt * ((this.gravity) ? this.gravity : 1) * PHYS_GRAVITY(this);
965  }
966  else
967  {
968  this.velocity = this.tic_velocity;
969  this.angles = this.tic_angles;
970  setorigin(this, this.tic_origin);
971  }
972 
973  this.flags = this.tic_flags;
974 
975  this.tic_saved_flags = this.flags;
976  this.tic_saved_velocity = this.velocity;
977  this.tic_saved_origin = this.origin;
978  this.tic_saved_avelocity = this.avelocity;
979  this.tic_saved_angles = this.angles;
980 }
const float SOLID_NOT
Definition: csprogsdefs.qc:244
void _Movetype_Physics_Push(entity this, float dt)
Definition: push.qc:201
float MOVETYPE_NONE
Definition: progsdefs.qc:246
#define PHYS_WALLCLIP(s)
Definition: movetypes.qh:43
const float SOLID_SLIDEBOX
Definition: csprogsdefs.qc:247
bool autocvar__movetype_debug
Definition: movetypes.qc:511
float MOVETYPE_WALK
Definition: progsdefs.qc:249
float trace_plane_dist
Definition: csprogsdefs.qc:39
#define X(v)
float watertype
Definition: progsdefs.qc:182
const int WATERLEVEL_SUBMERGED
Definition: movetypes.qh:14
vector view_ofs
Definition: progsdefs.qc:151
float trace_dphitq3surfaceflags
#define GAMEPLAYFIX_WATERTRANSITION(s)
Definition: movetypes.qh:29
vector _Movetype_ClipVelocity(vector vel, vector norm, float f)
Definition: movetypes.qc:668
const float MOVETYPE_PHYSICS
const int MAX_CLIP_PLANES
Definition: movetypes.qh:127
float waterlevel
Definition: progsdefs.qc:181
#define GAMEPLAYFIX_EASIERWATERJUMP(s)
Definition: movetypes.qh:24
bool _Movetype_CheckWater(entity this)
Definition: movetypes.qc:345
float MOVETYPE_STEP
Definition: progsdefs.qc:250
float FL_ONGROUND
Definition: progsdefs.qc:240
float MOVETYPE_TOSS
Definition: progsdefs.qc:252
float DPCONTENTS_MONSTERCLIP
bool move_qcphysics
Definition: physics.qh:25
vector oldorigin
Definition: csprogsdefs.qc:102
float trace_dphitcontents
entity() spawn
vector move_stepnormal
Definition: movetypes.qh:103
#define vec3(_x, _y, _z)
Definition: vector.qh:95
const float MOVE_NORMAL
Definition: csprogsdefs.qc:252
float MOVETYPE_BOUNCEMISSILE
Definition: progsdefs.qc:257
#define IS_ONGROUND(s)
Definition: movetypes.qh:16
vector maxs
Definition: csprogsdefs.qc:113
bool _Movetype_TestEntityPosition_Offset(int offset)
Definition: movetypes.qc:605
#define GAMEPLAYFIX_UNSTICKPLAYERS(s)
Definition: movetypes.qh:28
float DPCONTENTS_PLAYERCLIP
void _Movetype_Physics_ClientFrame(entity this, float movedt)
Definition: movetypes.qc:763
origin
Definition: ent_cs.qc:114
#define GAMEPLAYFIX_DELAYPROJECTILES(s)
Definition: movetypes.qh:35
void Movetype_Physics_NoMatchServer(entity this)
Definition: movetypes.qc:839
string classname
Definition: csprogsdefs.qc:107
vector avelocity
Definition: csprogsdefs.qc:105
float MOVETYPE_BOUNCE
Definition: progsdefs.qc:256
vector tic_saved_angles
Definition: movetypes.qc:868
float FL_ITEM
Definition: progsdefs.qc:239
void Movetype_Physics_NoMatchTicrate(entity this, float movedt, bool isclient)
Definition: movetypes.qc:813
int tic_flags
Definition: movetypes.qc:859
ERASEABLE bool IL_CONTAINS(IntrusiveList this, entity it)
void _Movetype_CheckStuck(entity this)
Definition: movetypes.qc:649
bool _Movetype_NudgeOutOfSolid_PivotIsKnownGood(entity this, vector pivot)
Definition: movetypes.qc:23
const int MOVETYPE_FAKEPUSH
Definition: movetypes.qh:154
float move_movetype
Definition: movetypes.qh:76
vector tic_velocity
Definition: movetypes.qc:858
const int WATERLEVEL_NONE
Definition: movetypes.qh:11
entity trace_ent
Definition: csprogsdefs.qc:40
int _Movetype_UnstickEntity(entity this)
Definition: movetypes.qc:622
string trace_dphittexturename
vector absmax
Definition: csprogsdefs.qc:92
float trace_inopen
Definition: csprogsdefs.qc:41
int _Movetype_ContentsMask(entity this)
Definition: movetypes.qc:559
float pm_time
Definition: movetypes.qh:74
const float CONTENT_EMPTY
Definition: csprogsdefs.qc:236
vector tic_saved_origin
Definition: movetypes.qc:864
entity groundentity
Definition: movetypes.qh:93
void _Movetype_CheckWaterTransition(entity ent)
Definition: movetypes.qc:379
const int UNSTICK_STUCK
Definition: movetypes.qh:100
const float MOVE_MISSILE
Definition: csprogsdefs.qc:254
vector tic_saved_avelocity
Definition: movetypes.qc:867
void _Movetype_Physics_Follow(entity this)
Definition: follow.qc:3
const float MOVE_NOMONSTERS
Definition: csprogsdefs.qc:253
vector mins
Definition: csprogsdefs.qc:113
#define vlen2(v)
Definition: vector.qh:4
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
void Movetype_Physics_MatchTicrate(entity this, float tr, bool sloppy)
Definition: movetypes.qc:869
void Movetype_Physics_MatchServer(entity this, bool sloppy)
Definition: movetypes.qc:851
ERASEABLE float boxesoverlap(vector m1, vector m2, vector m3, vector m4)
requires that m2>m1 in all coordinates, and that m4>m3
Definition: vector.qh:73
vector tic_avelocity
Definition: movetypes.qc:860
entity _Movetype_TestEntityPosition_ent
Definition: movetypes.qc:583
const float CONTENT_WATER
Definition: csprogsdefs.qc:238
const int MOVETYPE_QCENTITY
Definition: movetypes.qh:152
float move_nomonsters
Definition: movetypes.qh:88
vector tic_angles
Definition: movetypes.qc:861
float MOVETYPE_PUSH
Definition: progsdefs.qc:253
float MOVETYPE_FLY_WORLDONLY
void _Movetype_Physics_Step(entity this, float dt)
Definition: step.qc:3
void _Movetype_Physics_Frame(entity this, float movedt)
Definition: movetypes.qc:724
void _Movetype_LinkEdict(entity this, bool touch_triggers)
Definition: movetypes.qc:512
void _Movetype_Physics_Walk(entity this, float dt)
Definition: walk.qc:3
#define NULL
Definition: post.qh:17
float trace_dpstartcontents
float DPCONTENTS_SOLID
int tic_saved_flags
Definition: movetypes.qc:866
void _Movetype_PushEntityTrace(entity this, vector push)
Definition: movetypes.qc:679
vector trace_endpos
Definition: csprogsdefs.qc:37
int _Movetype_FlyMove(entity this, float dt, bool applygravity, bool applystepnormal, float stepheight)
Definition: movetypes.qc:124
const int WATERLEVEL_WETFEET
Definition: movetypes.qh:12
vector planes[MAX_CLIP_PLANES]
Definition: movetypes.qc:123
float move_didgravity
Definition: movetypes.qh:95
vector(float skel, float bonenum) _skel_get_boneabs_hidden
float gravity
Definition: items.qh:16
float MOVETYPE_FLYMISSILE
Definition: progsdefs.qc:255
float MOVETYPE_NOCLIP
Definition: progsdefs.qc:254
const float SOLID_BSP
Definition: csprogsdefs.qc:248
float DPCONTENTS_BODY
float flags
Definition: csprogsdefs.qc:129
float move_time
Definition: movetypes.qh:77
#define SET_ONGROUND(s)
Definition: movetypes.qh:17
float MOVETYPE_FOLLOW
void _Movetype_Physics_Toss(entity this, float dt)
Definition: toss.qc:3
vector tic_saved_velocity
Definition: movetypes.qc:865
void _Movetype_Impact(entity this, entity oth)
Definition: movetypes.qc:412
const float SOLID_TRIGGER
Definition: csprogsdefs.qc:245
const int UNSTICK_FINE
Definition: movetypes.qh:98
float trace_inwater
Definition: csprogsdefs.qc:42
const int WATERLEVEL_SWIMMING
Definition: movetypes.qh:13
#define cross(a, b)
Definition: vector.qh:25
setorigin(ent, v)
float dphitcontentsmask
vector trace_plane_normal
Definition: csprogsdefs.qc:38
bool _Movetype_TestEntityPosition(vector ofs)
Definition: movetypes.qc:584
IntrusiveList g_moveables
Definition: world.qh:160
vector angles
Definition: csprogsdefs.qc:104
float DPCONTENTS_LIQUIDSMASK
float trace_startsolid
Definition: csprogsdefs.qc:35
float movetype
Definition: csprogsdefs.qc:98
float FL_MONSTER
Definition: progsdefs.qc:236
vector tic_origin
Definition: movetypes.qc:857
vector absmin
Definition: csprogsdefs.qc:92
if(IS_DEAD(this))
Definition: impulse.qc:92
float MOVE_WORLDONLY
float trace_allsolid
Definition: csprogsdefs.qc:34
bool _Movetype_PushEntity(entity this, vector push, bool failonstartsolid, bool dolink)
Definition: movetypes.qc:697
void _Movetype_CheckVelocity(entity this)
Definition: movetypes.qc:339
float time
Definition: csprogsdefs.qc:16
const int UNSTICK_FIXED
Definition: movetypes.qh:99
vector velocity
Definition: csprogsdefs.qc:103
void _Movetype_WallFriction(entity this, vector stepnormal)
Definition: movetypes.qc:106
int dir
Definition: impulse.qc:89
float trace_fraction
Definition: csprogsdefs.qc:36
void _Movetype_LinkEdict_TouchAreaGrid(entity this)
Definition: movetypes.qc:453
void set_movetype(entity this, int mt)
float MOVETYPE_FLY
Definition: progsdefs.qc:251
#define LOG_DEBUGF(...)
Definition: log.qh:86
float DPCONTENTS_CORPSE
float FL_WATERJUMP
Definition: progsdefs.qc:242
#define LOG_DEBUG(...)
Definition: log.qh:85
float solid
Definition: csprogsdefs.qc:99
const float SOLID_CORPSE
Definition: csprogsdefs.qc:249