vkQuake2 doxygen  1.0 dev
g_phys.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 
19 */
20 // g_phys.c
21 
22 #include "g_local.h"
23 
24 /*
25 
26 
27 pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
28 
29 onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
30 
31 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
32 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
33 corpses are SOLID_NOT and MOVETYPE_TOSS
34 crates are SOLID_BBOX and MOVETYPE_TOSS
35 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
36 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
37 
38 solid_edge items only clip against bsp models.
39 
40 */
41 
42 
43 /*
44 ============
45 SV_TestEntityPosition
46 
47 ============
48 */
50 {
51  trace_t trace;
52  int mask;
53 
54  if (ent->clipmask)
55  mask = ent->clipmask;
56  else
57  mask = MASK_SOLID;
58  trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, mask);
59 
60  if (trace.startsolid)
61  return g_edicts;
62 
63  return NULL;
64 }
65 
66 
67 /*
68 ================
69 SV_CheckVelocity
70 ================
71 */
73 {
74  int i;
75 
76 //
77 // bound velocity
78 //
79  for (i=0 ; i<3 ; i++)
80  {
81  if (ent->velocity[i] > sv_maxvelocity->value)
82  ent->velocity[i] = sv_maxvelocity->value;
83  else if (ent->velocity[i] < -sv_maxvelocity->value)
84  ent->velocity[i] = -sv_maxvelocity->value;
85  }
86 }
87 
88 /*
89 =============
90 SV_RunThink
91 
92 Runs thinking code for this frame if necessary
93 =============
94 */
96 {
97  float thinktime;
98 
99  thinktime = ent->nextthink;
100  if (thinktime <= 0)
101  return true;
102  if (thinktime > level.time+0.001)
103  return true;
104 
105  ent->nextthink = 0;
106  if (!ent->think)
107  gi.error ("NULL ent->think");
108  ent->think (ent);
109 
110  return false;
111 }
112 
113 /*
114 ==================
115 SV_Impact
116 
117 Two entities have touched, so run their touch functions
118 ==================
119 */
120 void SV_Impact (edict_t *e1, trace_t *trace)
121 {
122  edict_t *e2;
123 // cplane_t backplane;
124 
125  e2 = trace->ent;
126 
127  if (e1->touch && e1->solid != SOLID_NOT)
128  e1->touch (e1, e2, &trace->plane, trace->surface);
129 
130  if (e2->touch && e2->solid != SOLID_NOT)
131  e2->touch (e2, e1, NULL, NULL);
132 }
133 
134 
135 /*
136 ==================
137 ClipVelocity
138 
139 Slide off of the impacting object
140 returns the blocked flags (1 = floor, 2 = step / wall)
141 ==================
142 */
143 #define STOP_EPSILON 0.1
144 
145 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
146 {
147  float backoff;
148  float change;
149  int i, blocked;
150 
151  blocked = 0;
152  if (normal[2] > 0)
153  blocked |= 1; // floor
154  if (!normal[2])
155  blocked |= 2; // step
156 
157  backoff = DotProduct (in, normal) * overbounce;
158 
159  for (i=0 ; i<3 ; i++)
160  {
161  change = normal[i]*backoff;
162  out[i] = in[i] - change;
163  if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
164  out[i] = 0;
165  }
166 
167  return blocked;
168 }
169 
170 
171 /*
172 ============
173 SV_FlyMove
174 
175 The basic solid body movement clip that slides along multiple planes
176 Returns the clipflags if the velocity was modified (hit something solid)
177 1 = floor
178 2 = wall / step
179 4 = dead stop
180 ============
181 */
182 #define MAX_CLIP_PLANES 5
183 int SV_FlyMove (edict_t *ent, float time, int mask)
184 {
185  edict_t *hit;
186  int bumpcount, numbumps;
187  vec3_t dir;
188  float d;
189  int numplanes;
190  vec3_t planes[MAX_CLIP_PLANES];
191  vec3_t primal_velocity, original_velocity, new_velocity;
192  int i, j;
193  trace_t trace;
194  vec3_t end;
195  float time_left;
196  int blocked;
197 
198  numbumps = 4;
199 
200  blocked = 0;
201  VectorCopy (ent->velocity, original_velocity);
202  VectorCopy (ent->velocity, primal_velocity);
203  numplanes = 0;
204 
205  time_left = time;
206 
207  ent->groundentity = NULL;
208  for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
209  {
210  for (i=0 ; i<3 ; i++)
211  end[i] = ent->s.origin[i] + time_left * ent->velocity[i];
212 
213  trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask);
214 
215  if (trace.allsolid)
216  { // entity is trapped in another solid
218  return 3;
219  }
220 
221  if (trace.fraction > 0)
222  { // actually covered some distance
223  VectorCopy (trace.endpos, ent->s.origin);
224  VectorCopy (ent->velocity, original_velocity);
225  numplanes = 0;
226  }
227 
228  if (trace.fraction == 1)
229  break; // moved the entire distance
230 
231  hit = trace.ent;
232 
233  if (trace.plane.normal[2] > 0.7)
234  {
235  blocked |= 1; // floor
236  if ( hit->solid == SOLID_BSP)
237  {
238  ent->groundentity = hit;
239  ent->groundentity_linkcount = hit->linkcount;
240  }
241  }
242  if (!trace.plane.normal[2])
243  {
244  blocked |= 2; // step
245  }
246 
247 //
248 // run the impact function
249 //
250  SV_Impact (ent, &trace);
251  if (!ent->inuse)
252  break; // removed by the impact function
253 
254 
255  time_left -= time_left * trace.fraction;
256 
257  // cliped to another plane
258  if (numplanes >= MAX_CLIP_PLANES)
259  { // this shouldn't really happen
261  return 3;
262  }
263 
264  VectorCopy (trace.plane.normal, planes[numplanes]);
265  numplanes++;
266 
267 //
268 // modify original_velocity so it parallels all of the clip planes
269 //
270  for (i=0 ; i<numplanes ; i++)
271  {
272  ClipVelocity (original_velocity, planes[i], new_velocity, 1);
273 
274  for (j=0 ; j<numplanes ; j++)
275  if ((j != i) && !VectorCompare (planes[i], planes[j]))
276  {
277  if (DotProduct (new_velocity, planes[j]) < 0)
278  break; // not ok
279  }
280  if (j == numplanes)
281  break;
282  }
283 
284  if (i != numplanes)
285  { // go along this plane
286  VectorCopy (new_velocity, ent->velocity);
287  }
288  else
289  { // go along the crease
290  if (numplanes != 2)
291  {
292 // gi.dprintf ("clip velocity, numplanes == %i\n",numplanes);
294  return 7;
295  }
296  CrossProduct (planes[0], planes[1], dir);
297  d = DotProduct (dir, ent->velocity);
298  VectorScale (dir, d, ent->velocity);
299  }
300 
301 //
302 // if original velocity is against the original velocity, stop dead
303 // to avoid tiny occilations in sloping corners
304 //
305  if (DotProduct (ent->velocity, primal_velocity) <= 0)
306  {
308  return blocked;
309  }
310  }
311 
312  return blocked;
313 }
314 
315 
316 /*
317 ============
318 SV_AddGravity
319 
320 ============
321 */
323 {
324  ent->velocity[2] -= ent->gravity * sv_gravity->value * FRAMETIME;
325 }
326 
327 /*
328 ===============================================================================
329 
330 PUSHMOVE
331 
332 ===============================================================================
333 */
334 
335 /*
336 ============
337 SV_PushEntity
338 
339 Does not change the entities velocity at all
340 ============
341 */
343 {
344  trace_t trace;
345  vec3_t start;
346  vec3_t end;
347  int mask;
348 
349  VectorCopy (ent->s.origin, start);
350  VectorAdd (start, push, end);
351 
352 retry:
353  if (ent->clipmask)
354  mask = ent->clipmask;
355  else
356  mask = MASK_SOLID;
357 
358  trace = gi.trace (start, ent->mins, ent->maxs, end, ent, mask);
359 
360  VectorCopy (trace.endpos, ent->s.origin);
361  gi.linkentity (ent);
362 
363  if (trace.fraction != 1.0)
364  {
365  SV_Impact (ent, &trace);
366 
367  // if the pushed entity went away and the pusher is still there
368  if (!trace.ent->inuse && ent->inuse)
369  {
370  // move the pusher back and try again
371  VectorCopy (start, ent->s.origin);
372  gi.linkentity (ent);
373  goto retry;
374  }
375  }
376 
377  if (ent->inuse)
378  G_TouchTriggers (ent);
379 
380  return trace;
381 }
382 
383 
384 typedef struct
385 {
389  float deltayaw;
390 } pushed_t;
392 
394 
395 /*
396 ============
397 SV_Push
398 
399 Objects need to be moved back on a failed push,
400 otherwise riders would continue to slide.
401 ============
402 */
403 qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove)
404 {
405  int i, e;
406  edict_t *check, *block;
407  vec3_t mins, maxs;
408  pushed_t *p;
409  vec3_t org, org2, move2, forward, right, up;
410 
411  // clamp the move to 1/8 units, so the position will
412  // be accurate for client side prediction
413  for (i=0 ; i<3 ; i++)
414  {
415  float temp;
416  temp = move[i]*8.0;
417  if (temp > 0.0)
418  temp += 0.5;
419  else
420  temp -= 0.5;
421  move[i] = 0.125 * (int)temp;
422  }
423 
424  // find the bounding box
425  for (i=0 ; i<3 ; i++)
426  {
427  mins[i] = pusher->absmin[i] + move[i];
428  maxs[i] = pusher->absmax[i] + move[i];
429  }
430 
431 // we need this for pushing things later
432  VectorSubtract (vec3_origin, amove, org);
433  AngleVectors (org, forward, right, up);
434 
435 // save the pusher's original position
436  pushed_p->ent = pusher;
437  VectorCopy (pusher->s.origin, pushed_p->origin);
438  VectorCopy (pusher->s.angles, pushed_p->angles);
439  if (pusher->client)
441  pushed_p++;
442 
443 // move the pusher to it's final position
444  VectorAdd (pusher->s.origin, move, pusher->s.origin);
445  VectorAdd (pusher->s.angles, amove, pusher->s.angles);
446  gi.linkentity (pusher);
447 
448 // see if any solid entities are inside the final position
449  check = g_edicts+1;
450  for (e = 1; e < globals.num_edicts; e++, check++)
451  {
452  if (!check->inuse)
453  continue;
454  if (check->movetype == MOVETYPE_PUSH
455  || check->movetype == MOVETYPE_STOP
456  || check->movetype == MOVETYPE_NONE
457  || check->movetype == MOVETYPE_NOCLIP)
458  continue;
459 
460  if (!check->area.prev)
461  continue; // not linked in anywhere
462 
463  // if the entity is standing on the pusher, it will definitely be moved
464  if (check->groundentity != pusher)
465  {
466  // see if the ent needs to be tested
467  if ( check->absmin[0] >= maxs[0]
468  || check->absmin[1] >= maxs[1]
469  || check->absmin[2] >= maxs[2]
470  || check->absmax[0] <= mins[0]
471  || check->absmax[1] <= mins[1]
472  || check->absmax[2] <= mins[2] )
473  continue;
474 
475  // see if the ent's bbox is inside the pusher's final position
476  if (!SV_TestEntityPosition (check))
477  continue;
478  }
479 
480  if ((pusher->movetype == MOVETYPE_PUSH) || (check->groundentity == pusher))
481  {
482  // move this entity
483  pushed_p->ent = check;
484  VectorCopy (check->s.origin, pushed_p->origin);
485  VectorCopy (check->s.angles, pushed_p->angles);
486  pushed_p++;
487 
488  // try moving the contacted entity
489  VectorAdd (check->s.origin, move, check->s.origin);
490  if (check->client)
491  { // FIXME: doesn't rotate monsters?
492  check->client->ps.pmove.delta_angles[YAW] += amove[YAW];
493  }
494 
495  // figure movement due to the pusher's amove
496  VectorSubtract (check->s.origin, pusher->s.origin, org);
497  org2[0] = DotProduct (org, forward);
498  org2[1] = -DotProduct (org, right);
499  org2[2] = DotProduct (org, up);
500  VectorSubtract (org2, org, move2);
501  VectorAdd (check->s.origin, move2, check->s.origin);
502 
503  // may have pushed them off an edge
504  if (check->groundentity != pusher)
505  check->groundentity = NULL;
506 
507  block = SV_TestEntityPosition (check);
508  if (!block)
509  { // pushed ok
510  gi.linkentity (check);
511  // impact?
512  continue;
513  }
514 
515  // if it is ok to leave in the old position, do it
516  // this is only relevent for riding entities, not pushed
517  // FIXME: this doesn't acount for rotation
518  VectorSubtract (check->s.origin, move, check->s.origin);
519  block = SV_TestEntityPosition (check);
520  if (!block)
521  {
522  pushed_p--;
523  continue;
524  }
525  }
526 
527  // save off the obstacle so we can call the block function
528  obstacle = check;
529 
530  // move back any entities we already moved
531  // go backwards, so if the same entity was pushed
532  // twice, it goes back to the original position
533  for (p=pushed_p-1 ; p>=pushed ; p--)
534  {
535  VectorCopy (p->origin, p->ent->s.origin);
536  VectorCopy (p->angles, p->ent->s.angles);
537  if (p->ent->client)
538  {
540  }
541  gi.linkentity (p->ent);
542  }
543  return false;
544  }
545 
546 //FIXME: is there a better way to handle this?
547  // see if anything we moved has touched a trigger
548  for (p=pushed_p-1 ; p>=pushed ; p--)
549  G_TouchTriggers (p->ent);
550 
551  return true;
552 }
553 
554 /*
555 ================
556 SV_Physics_Pusher
557 
558 Bmodel objects don't interact with each other, but
559 push all box objects
560 ================
561 */
563 {
564  vec3_t move, amove;
565  edict_t *part, *mv;
566 
567  // if not a team captain, so movement will be handled elsewhere
568  if ( ent->flags & FL_TEAMSLAVE)
569  return;
570 
571  // make sure all team slaves can move before commiting
572  // any moves or calling any think functions
573  // if the move is blocked, all moved objects will be backed out
574 //retry:
575  pushed_p = pushed;
576  for (part = ent ; part ; part=part->teamchain)
577  {
578  if (part->velocity[0] || part->velocity[1] || part->velocity[2] ||
579  part->avelocity[0] || part->avelocity[1] || part->avelocity[2]
580  )
581  { // object is moving
582  VectorScale (part->velocity, FRAMETIME, move);
583  VectorScale (part->avelocity, FRAMETIME, amove);
584 
585  if (!SV_Push (part, move, amove))
586  break; // move was blocked
587  }
588  }
589  if (pushed_p > &pushed[MAX_EDICTS])
590  gi.error (ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted");
591 
592  if (part)
593  {
594  // the move failed, bump all nextthink times and back out moves
595  for (mv = ent ; mv ; mv=mv->teamchain)
596  {
597  if (mv->nextthink > 0)
598  mv->nextthink += FRAMETIME;
599  }
600 
601  // if the pusher has a "blocked" function, call it
602  // otherwise, just stay in place until the obstacle is gone
603  if (part->blocked)
604  part->blocked (part, obstacle);
605 #if 0
606  // if the pushed entity went away and the pusher is still there
607  if (!obstacle->inuse && part->inuse)
608  goto retry;
609 #endif
610  }
611  else
612  {
613  // the move succeeded, so call all think functions
614  for (part = ent ; part ; part=part->teamchain)
615  {
616  SV_RunThink (part);
617  }
618  }
619 }
620 
621 //==================================================================
622 
623 /*
624 =============
625 SV_Physics_None
626 
627 Non moving objects can only think
628 =============
629 */
631 {
632 // regular thinking
633  SV_RunThink (ent);
634 }
635 
636 /*
637 =============
638 SV_Physics_Noclip
639 
640 A moving object that doesn't obey physics
641 =============
642 */
644 {
645 // regular thinking
646  if (!SV_RunThink (ent))
647  return;
648 
649  VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
650  VectorMA (ent->s.origin, FRAMETIME, ent->velocity, ent->s.origin);
651 
652  gi.linkentity (ent);
653 }
654 
655 /*
656 ==============================================================================
657 
658 TOSS / BOUNCE
659 
660 ==============================================================================
661 */
662 
663 /*
664 =============
665 SV_Physics_Toss
666 
667 Toss, bounce, and fly movement. When onground, do nothing.
668 =============
669 */
671 {
672  trace_t trace;
673  vec3_t move;
674  float backoff;
675  edict_t *slave;
676  qboolean wasinwater;
677  qboolean isinwater;
678  vec3_t old_origin;
679 
680 // regular thinking
681  SV_RunThink (ent);
682 
683  // if not a team captain, so movement will be handled elsewhere
684  if ( ent->flags & FL_TEAMSLAVE)
685  return;
686 
687  if (ent->velocity[2] > 0)
688  ent->groundentity = NULL;
689 
690 // check for the groundentity going away
691  if (ent->groundentity)
692  if (!ent->groundentity->inuse)
693  ent->groundentity = NULL;
694 
695 // if onground, return without moving
696  if ( ent->groundentity )
697  return;
698 
699  VectorCopy (ent->s.origin, old_origin);
700 
701  SV_CheckVelocity (ent);
702 
703 // add gravity
704  if (ent->movetype != MOVETYPE_FLY
705  && ent->movetype != MOVETYPE_FLYMISSILE)
706  SV_AddGravity (ent);
707 
708 // move angles
709  VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
710 
711 // move origin
712  VectorScale (ent->velocity, FRAMETIME, move);
713  trace = SV_PushEntity (ent, move);
714  if (!ent->inuse)
715  return;
716 
717  if (trace.fraction < 1)
718  {
719  if (ent->movetype == MOVETYPE_BOUNCE)
720  backoff = 1.5;
721  else
722  backoff = 1;
723 
724  ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff);
725 
726  // stop if on ground
727  if (trace.plane.normal[2] > 0.7)
728  {
729  if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE )
730  {
731  ent->groundentity = trace.ent;
732  ent->groundentity_linkcount = trace.ent->linkcount;
735  }
736  }
737 
738 // if (ent->touch)
739 // ent->touch (ent, trace.ent, &trace.plane, trace.surface);
740  }
741 
742 // check for water transition
743  wasinwater = (ent->watertype & MASK_WATER);
744  ent->watertype = gi.pointcontents (ent->s.origin);
745  isinwater = ent->watertype & MASK_WATER;
746 
747  if (isinwater)
748  ent->waterlevel = 1;
749  else
750  ent->waterlevel = 0;
751 
752  if (!wasinwater && isinwater)
753  gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
754  else if (wasinwater && !isinwater)
755  gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
756 
757 // move teamslaves
758  for (slave = ent->teamchain; slave; slave = slave->teamchain)
759  {
760  VectorCopy (ent->s.origin, slave->s.origin);
761  gi.linkentity (slave);
762  }
763 }
764 
765 /*
766 ===============================================================================
767 
768 STEPPING MOVEMENT
769 
770 ===============================================================================
771 */
772 
773 /*
774 =============
775 SV_Physics_Step
776 
777 Monsters freefall when they don't have a ground entity, otherwise
778 all movement is done with discrete steps.
779 
780 This is also used for objects that have become still on the ground, but
781 will fall if the floor is pulled out from under them.
782 FIXME: is this true?
783 =============
784 */
785 
786 //FIXME: hacked in for E3 demo
787 #define sv_stopspeed 100
788 #define sv_friction 6
789 #define sv_waterfriction 1
790 
792 {
793  int n;
794  float adjustment;
795 
796  VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
797  adjustment = FRAMETIME * sv_stopspeed * sv_friction;
798  for (n = 0; n < 3; n++)
799  {
800  if (ent->avelocity[n] > 0)
801  {
802  ent->avelocity[n] -= adjustment;
803  if (ent->avelocity[n] < 0)
804  ent->avelocity[n] = 0;
805  }
806  else
807  {
808  ent->avelocity[n] += adjustment;
809  if (ent->avelocity[n] > 0)
810  ent->avelocity[n] = 0;
811  }
812  }
813 }
814 
816 {
817  qboolean wasonground;
818  qboolean hitsound = false;
819  float *vel;
820  float speed, newspeed, control;
821  float friction;
822  edict_t *groundentity;
823  int mask;
824 
825  // airborn monsters should always check for ground
826  if (!ent->groundentity)
827  M_CheckGround (ent);
828 
829  groundentity = ent->groundentity;
830 
831  SV_CheckVelocity (ent);
832 
833  if (groundentity)
834  wasonground = true;
835  else
836  wasonground = false;
837 
838  if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
840 
841  // add gravity except:
842  // flying monsters
843  // swimming monsters who are in the water
844  if (! wasonground)
845  if (!(ent->flags & FL_FLY))
846  if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
847  {
848  if (ent->velocity[2] < sv_gravity->value*-0.1)
849  hitsound = true;
850  if (ent->waterlevel == 0)
851  SV_AddGravity (ent);
852  }
853 
854  // friction for flying monsters that have been given vertical velocity
855  if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
856  {
857  speed = fabs(ent->velocity[2]);
858  control = speed < sv_stopspeed ? sv_stopspeed : speed;
859  friction = sv_friction/3;
860  newspeed = speed - (FRAMETIME * control * friction);
861  if (newspeed < 0)
862  newspeed = 0;
863  newspeed /= speed;
864  ent->velocity[2] *= newspeed;
865  }
866 
867  // friction for flying monsters that have been given vertical velocity
868  if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
869  {
870  speed = fabs(ent->velocity[2]);
871  control = speed < sv_stopspeed ? sv_stopspeed : speed;
872  newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
873  if (newspeed < 0)
874  newspeed = 0;
875  newspeed /= speed;
876  ent->velocity[2] *= newspeed;
877  }
878 
879  if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
880  {
881  // apply friction
882  // let dead monsters who aren't completely onground slide
883  if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
884  if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
885  {
886  vel = ent->velocity;
887  speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
888  if (speed)
889  {
890  friction = sv_friction;
891 
892  control = speed < sv_stopspeed ? sv_stopspeed : speed;
893  newspeed = speed - FRAMETIME*control*friction;
894 
895  if (newspeed < 0)
896  newspeed = 0;
897  newspeed /= speed;
898 
899  vel[0] *= newspeed;
900  vel[1] *= newspeed;
901  }
902  }
903 
904  if (ent->svflags & SVF_MONSTER)
906  else
907  mask = MASK_SOLID;
908  SV_FlyMove (ent, FRAMETIME, mask);
909 
910  gi.linkentity (ent);
911  G_TouchTriggers (ent);
912  if (!ent->inuse)
913  return;
914 
915  if (ent->groundentity)
916  if (!wasonground)
917  if (hitsound)
918  gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
919  }
920 
921 // regular thinking
922  SV_RunThink (ent);
923 }
924 
925 //============================================================================
926 /*
927 ================
928 G_RunEntity
929 
930 ================
931 */
932 void G_RunEntity (edict_t *ent)
933 {
934  if (ent->prethink)
935  ent->prethink (ent);
936 
937  switch ( (int)ent->movetype)
938  {
939  case MOVETYPE_PUSH:
940  case MOVETYPE_STOP:
941  SV_Physics_Pusher (ent);
942  break;
943  case MOVETYPE_NONE:
944  SV_Physics_None (ent);
945  break;
946  case MOVETYPE_NOCLIP:
947  SV_Physics_Noclip (ent);
948  break;
949  case MOVETYPE_STEP:
950  SV_Physics_Step (ent);
951  break;
952  case MOVETYPE_TOSS:
953  case MOVETYPE_BOUNCE:
954  case MOVETYPE_FLY:
955  case MOVETYPE_FLYMISSILE:
956  SV_Physics_Toss (ent);
957  break;
958  default:
959  gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype);
960  }
961 }
gi
game_import_t gi
Definition: g_main.c:25
cplane_s::normal
vec3_t normal
Definition: q_shared.h:415
edict_s::s
entity_state_t s
Definition: g_local.h:970
edict_s::groundentity
edict_t * groundentity
Definition: g_local.h:1079
sv_waterfriction
#define sv_waterfriction
Definition: g_phys.c:789
YAW
#define YAW
Definition: q_shared.h:73
MASK_MONSTERSOLID
#define MASK_MONSTERSOLID
Definition: q_shared.h:398
pushed_t::ent
edict_t * ent
Definition: g_phys.c:386
game_import_t::trace
trace_t(* trace)(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passent, int contentmask)
Definition: game.h:128
trace_t::fraction
float fraction
Definition: q_shared.h:457
int
CONST PIXELFORMATDESCRIPTOR int
Definition: qgl_win.c:35
VectorSubtract
#define VectorSubtract(a, b, c)
Definition: q_shared.h:163
edict_s::absmax
vec3_t absmax
Definition: g_local.h:991
trace_t::plane
cplane_t plane
Definition: q_shared.h:459
FRAMETIME
#define FRAMETIME
Definition: g_local.h:75
obstacle
edict_t * obstacle
Definition: g_phys.c:393
pushed_t::deltayaw
float deltayaw
Definition: g_phys.c:389
MOVETYPE_NOCLIP
@ MOVETYPE_NOCLIP
Definition: g_local.h:191
MOVETYPE_STOP
@ MOVETYPE_STOP
Definition: g_local.h:193
numplanes
int numplanes
Definition: cmodel.c:71
entity_state_s::origin
vec3_t origin
Definition: q_shared.h:1149
edict_s::linkcount
int linkcount
Definition: g_local.h:977
SV_CheckVelocity
void SV_CheckVelocity(edict_t *ent)
Definition: g_phys.c:72
sv_friction
#define sv_friction
Definition: g_phys.c:788
MASK_WATER
#define MASK_WATER
Definition: q_shared.h:399
VectorScale
void VectorScale(vec3_t in, vec_t scale, vec3_t out)
Definition: q_shared.c:782
pushed_t::origin
vec3_t origin
Definition: g_phys.c:387
qboolean
qboolean
Definition: q_shared.h:63
SV_Physics_Noclip
void SV_Physics_Noclip(edict_t *ent)
Definition: g_phys.c:643
edict_s::inuse
qboolean inuse
Definition: g_local.h:976
trace_t
Definition: q_shared.h:453
i
int i
Definition: q_shared.c:305
G_TouchTriggers
void G_TouchTriggers(edict_t *ent)
Definition: g_utils.c:475
MOVETYPE_PUSH
@ MOVETYPE_PUSH
Definition: g_local.h:192
MOVETYPE_FLYMISSILE
@ MOVETYPE_FLYMISSILE
Definition: g_local.h:199
pushed_p
pushed_t * pushed_p
Definition: g_phys.c:391
SV_Impact
void SV_Impact(edict_t *e1, trace_t *trace)
Definition: g_phys.c:120
edict_s::client
struct gclient_s * client
Definition: g_local.h:971
game_import_t::sound
void(* sound)(edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs)
Definition: game.h:109
edict_s::blocked
void(* blocked)(edict_t *self, edict_t *other)
Definition: g_local.h:1045
SV_Physics_Pusher
void SV_Physics_Pusher(edict_t *ent)
Definition: g_phys.c:562
edict_s::mins
vec3_t mins
Definition: g_local.h:990
edict_s::prethink
void(* prethink)(edict_t *ent)
Definition: g_local.h:1043
SV_AddGravity
void SV_AddGravity(edict_t *ent)
Definition: g_phys.c:322
g_edicts
edict_t * g_edicts
Definition: g_main.c:33
edict_s::groundentity_linkcount
int groundentity_linkcount
Definition: g_local.h:1080
edict_s::movetype
int movetype
Definition: g_local.h:1001
MOVETYPE_STEP
@ MOVETYPE_STEP
Definition: g_local.h:196
FL_SWIM
#define FL_SWIM
Definition: g_local.h:60
j
GLint j
Definition: qgl_win.c:150
MASK_SOLID
#define MASK_SOLID
Definition: q_shared.h:395
CHAN_AUTO
#define CHAN_AUTO
Definition: q_shared.h:983
AngleVectors
void AngleVectors(vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Definition: q_shared.c:93
ClipVelocity
int ClipVelocity(vec3_t in, vec3_t normal, vec3_t out, float overbounce)
Definition: g_phys.c:145
trace_t::allsolid
qboolean allsolid
Definition: q_shared.h:455
edict_s::svflags
int svflags
Definition: g_local.h:989
CrossProduct
void CrossProduct(vec3_t v1, vec3_t v2, vec3_t cross)
Definition: q_shared.c:753
edict_s
Definition: g_local.h:968
SV_AddRotationalFriction
void SV_AddRotationalFriction(edict_t *ent)
Definition: g_phys.c:791
MOVETYPE_NONE
@ MOVETYPE_NONE
Definition: g_local.h:190
SV_Physics_None
void SV_Physics_None(edict_t *ent)
Definition: g_phys.c:630
game_import_t::soundindex
int(* soundindex)(char *name)
Definition: game.h:122
forward
static vec3_t forward
Definition: p_view.c:29
edict_s::clipmask
int clipmask
Definition: g_local.h:993
player_state_t::pmove
pmove_state_t pmove
Definition: q_shared.h:1176
game_import_t::pointcontents
int(* pointcontents)(vec3_t point)
Definition: game.h:129
DotProduct
#define DotProduct(x, y)
Definition: q_shared.h:162
game_import_t::positioned_sound
void(* positioned_sound)(vec3_t origin, edict_t *ent, int channel, int soundinedex, float volume, float attenuation, float timeofs)
Definition: game.h:110
edict_s::nextthink
float nextthink
Definition: g_local.h:1042
cvar_s::value
float value
Definition: q_shared.h:331
edict_s::think
void(* think)(edict_t *self)
Definition: g_local.h:1044
STOP_EPSILON
#define STOP_EPSILON
Definition: g_phys.c:143
pmove_state_t::delta_angles
short delta_angles[3]
Definition: q_shared.h:503
M_CheckBottom
qboolean M_CheckBottom(edict_t *ent)
Definition: m_move.c:37
gclient_s::ps
player_state_t ps
Definition: g_local.h:886
edict_s::watertype
int watertype
Definition: g_local.h:1099
NULL
#define NULL
Definition: q_shared.h:67
globals
game_export_t globals
Definition: g_main.c:26
edict_s::solid
solid_t solid
Definition: g_local.h:992
SOLID_NOT
@ SOLID_NOT
Definition: game.h:35
MAX_EDICTS
#define MAX_EDICTS
Definition: q_shared.h:87
edict_s::velocity
vec3_t velocity
Definition: g_local.h:1030
ERR_FATAL
#define ERR_FATAL
Definition: qcommon.h:743
SV_PushEntity
trace_t SV_PushEntity(edict_t *ent, vec3_t push)
Definition: g_phys.c:342
VectorAdd
#define VectorAdd(a, b, c)
Definition: q_shared.h:164
M_CheckGround
void M_CheckGround(edict_t *ent)
Definition: g_monster.c:141
SV_FlyMove
int SV_FlyMove(edict_t *ent, float time, int mask)
Definition: g_phys.c:183
game_import_t::error
void(* error)(char *fmt,...)
Definition: game.h:118
VectorCopy
#define VectorCopy(a, b)
Definition: q_shared.h:165
MAX_CLIP_PLANES
#define MAX_CLIP_PLANES
Definition: g_phys.c:182
trace_t::endpos
vec3_t endpos
Definition: q_shared.h:458
vec3_origin
vec3_t vec3_origin
Definition: q_shared.c:24
up
static vec3_t up
Definition: p_view.c:29
pushed_t
Definition: g_phys.c:384
level
GLint level
Definition: qgl_win.c:116
SV_Push
qboolean SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
Definition: g_phys.c:403
edict_s::flags
int flags
Definition: g_local.h:1002
FL_TEAMSLAVE
#define FL_TEAMSLAVE
Definition: g_local.h:69
pushed_t::angles
vec3_t angles
Definition: g_phys.c:388
sqrt
double sqrt(double x)
VectorMA
void VectorMA(vec3_t veca, float scale, vec3_t vecb, vec3_t vecc)
Definition: q_shared.c:719
SOLID_BSP
@ SOLID_BSP
Definition: game.h:38
G_RunEntity
void G_RunEntity(edict_t *ent)
Definition: g_phys.c:932
edict_s::maxs
vec3_t maxs
Definition: g_local.h:990
edict_s::avelocity
vec3_t avelocity
Definition: g_local.h:1031
trace_t::startsolid
qboolean startsolid
Definition: q_shared.h:456
edict_s::gravity
float gravity
Definition: g_local.h:1034
trace_t::ent
struct edict_s * ent
Definition: q_shared.h:462
FL_FLY
#define FL_FLY
Definition: g_local.h:59
SVF_MONSTER
#define SVF_MONSTER
Definition: game.h:29
edict_s::touch
void(* touch)(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
Definition: g_local.h:1046
SV_TestEntityPosition
edict_t * SV_TestEntityPosition(edict_t *ent)
Definition: g_phys.c:49
MOVETYPE_BOUNCE
@ MOVETYPE_BOUNCE
Definition: g_local.h:200
trace_t::surface
csurface_t * surface
Definition: q_shared.h:460
sv_gravity
cvar_t * sv_gravity
Definition: g_main.c:53
SV_Physics_Toss
void SV_Physics_Toss(edict_t *ent)
Definition: g_phys.c:670
MOVETYPE_TOSS
@ MOVETYPE_TOSS
Definition: g_local.h:198
right
GLdouble right
Definition: qgl_win.c:159
pushed
pushed_t pushed[MAX_EDICTS]
Definition: g_phys.c:391
sv_maxvelocity
cvar_t * sv_maxvelocity
Definition: g_main.c:52
edict_s::waterlevel
int waterlevel
Definition: g_local.h:1100
edict_s::area
link_t area
Definition: g_local.h:980
VectorCompare
int VectorCompare(vec3_t v1, vec3_t v2)
Definition: q_shared.c:672
mask
GLint GLuint mask
Definition: qgl_win.c:317
edict_s::teamchain
edict_t * teamchain
Definition: g_local.h:1081
game_import_t::linkentity
void(* linkentity)(edict_t *ent)
Definition: game.h:138
entity_state_s::angles
vec3_t angles
Definition: q_shared.h:1150
sv_stopspeed
#define sv_stopspeed
Definition: g_phys.c:787
SV_Physics_Step
void SV_Physics_Step(edict_t *ent)
Definition: g_phys.c:815
vec3_t
vec_t vec3_t[3]
Definition: q_shared.h:134
edict_s::absmin
vec3_t absmin
Definition: g_local.h:991
MOVETYPE_FLY
@ MOVETYPE_FLY
Definition: g_local.h:197
game_export_t::num_edicts
int num_edicts
Definition: game.h:231
SV_RunThink
qboolean SV_RunThink(edict_t *ent)
Definition: g_phys.c:95
g_local.h
edict_s::health
int health
Definition: g_local.h:1057