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