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