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 */
SV_TestEntityPosition(edict_t * ent)49 edict_t *SV_TestEntityPosition (edict_t *ent)
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 */
SV_CheckVelocity(edict_t * ent)72 void SV_CheckVelocity (edict_t *ent)
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 */
SV_RunThink(edict_t * ent)95 qboolean SV_RunThink (edict_t *ent)
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 */
SV_Impact(edict_t * e1,trace_t * trace)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
ClipVelocity(vec3_t in,vec3_t normal,vec3_t out,float overbounce)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
SV_FlyMove(edict_t * ent,float time,int mask)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
217 VectorCopy (vec3_origin, ent->velocity);
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
260 VectorCopy (vec3_origin, ent->velocity);
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);
293 VectorCopy (vec3_origin, ent->velocity);
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 {
307 VectorCopy (vec3_origin, ent->velocity);
308 return blocked;
309 }
310 }
311
312 return blocked;
313 }
314
315
316 /*
317 ============
318 SV_AddGravity
319
320 ============
321 */
SV_AddGravity(edict_t * ent)322 void SV_AddGravity (edict_t *ent)
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 */
SV_PushEntity(edict_t * ent,vec3_t push)342 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
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 if (trace.startsolid || trace.allsolid)
361 {
362 mask ^= CONTENTS_DEADMONSTER;
363 trace = gi.trace (start, ent->mins, ent->maxs, end, ent, mask);
364 }
365
366 VectorCopy (trace.endpos, ent->s.origin);
367 gi.linkentity (ent);
368
369 if (trace.fraction != 1.0)
370 {
371 SV_Impact (ent, &trace);
372
373 // if the pushed entity went away and the pusher is still there
374 if (!trace.ent->inuse && ent->inuse)
375 {
376 // move the pusher back and try again
377 VectorCopy (start, ent->s.origin);
378 gi.linkentity (ent);
379 goto retry;
380 }
381 }
382
383 if (ent->inuse)
384 G_TouchTriggers (ent);
385
386 return trace;
387 }
388
389
390 typedef struct
391 {
392 edict_t *ent;
393 vec3_t origin;
394 vec3_t angles;
395 float deltayaw;
396 } pushed_t;
397 pushed_t pushed[MAX_EDICTS], *pushed_p;
398
399 edict_t *obstacle;
400
401 /*
402 ============
403 SV_Push
404
405 Objects need to be moved back on a failed push,
406 otherwise riders would continue to slide.
407 ============
408 */
SV_Push(edict_t * pusher,vec3_t move,vec3_t amove)409 qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove)
410 {
411 int i, e;
412 edict_t *check, *block;
413 vec3_t mins, maxs;
414 pushed_t *p;
415 vec3_t org, org2, move2, forward, right, up;
416
417 // clamp the move to 1/8 units, so the position will
418 // be accurate for client side prediction
419 for (i=0 ; i<3 ; i++)
420 {
421 float temp;
422 temp = move[i]*8.0;
423 if (temp > 0.0)
424 temp += 0.5;
425 else
426 temp -= 0.5;
427 move[i] = 0.125 * (int)temp;
428 }
429
430 // find the bounding box
431 for (i=0 ; i<3 ; i++)
432 {
433 mins[i] = pusher->absmin[i] + move[i];
434 maxs[i] = pusher->absmax[i] + move[i];
435 }
436
437 // we need this for pushing things later
438 VectorSubtract (vec3_origin, amove, org);
439 AngleVectors (org, forward, right, up);
440
441 // save the pusher's original position
442 pushed_p->ent = pusher;
443 VectorCopy (pusher->s.origin, pushed_p->origin);
444 VectorCopy (pusher->s.angles, pushed_p->angles);
445 if (pusher->client)
446 pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW];
447 pushed_p++;
448
449 // move the pusher to it's final position
450 VectorAdd (pusher->s.origin, move, pusher->s.origin);
451 VectorAdd (pusher->s.angles, amove, pusher->s.angles);
452 gi.linkentity (pusher);
453
454 // see if any solid entities are inside the final position
455 check = g_edicts+1;
456 for (e = 1; e < globals.num_edicts; e++, check++)
457 {
458 if (!check->inuse)
459 continue;
460 if (check->movetype == MOVETYPE_PUSH
461 || check->movetype == MOVETYPE_STOP
462 || check->movetype == MOVETYPE_NONE
463 || check->movetype == MOVETYPE_NOCLIP)
464 continue;
465
466 if (!check->area.prev)
467 continue; // not linked in anywhere
468
469 // if the entity is standing on the pusher, it will definitely be moved
470 if (check->groundentity != pusher)
471 {
472 // see if the ent needs to be tested
473 if ( check->absmin[0] >= maxs[0]
474 || check->absmin[1] >= maxs[1]
475 || check->absmin[2] >= maxs[2]
476 || check->absmax[0] <= mins[0]
477 || check->absmax[1] <= mins[1]
478 || check->absmax[2] <= mins[2] )
479 continue;
480
481 // see if the ent's bbox is inside the pusher's final position
482 if (!SV_TestEntityPosition (check))
483 continue;
484 }
485
486 if ((pusher->movetype == MOVETYPE_PUSH) || (check->groundentity == pusher))
487 {
488 // move this entity
489 pushed_p->ent = check;
490 VectorCopy (check->s.origin, pushed_p->origin);
491 VectorCopy (check->s.angles, pushed_p->angles);
492 pushed_p++;
493
494 // try moving the contacted entity
495 VectorAdd (check->s.origin, move, check->s.origin);
496 if (check->client)
497 { // FIXME: doesn't rotate monsters?
498 check->client->ps.pmove.delta_angles[YAW] += amove[YAW];
499 }
500
501 // figure movement due to the pusher's amove
502 VectorSubtract (check->s.origin, pusher->s.origin, org);
503 org2[0] = DotProduct (org, forward);
504 org2[1] = -DotProduct (org, right);
505 org2[2] = DotProduct (org, up);
506 VectorSubtract (org2, org, move2);
507 VectorAdd (check->s.origin, move2, check->s.origin);
508
509 // may have pushed them off an edge
510 if (check->groundentity != pusher)
511 check->groundentity = NULL;
512
513 block = SV_TestEntityPosition (check);
514 if (!block)
515 { // pushed ok
516 gi.linkentity (check);
517 // impact?
518 continue;
519 }
520
521 // if it is ok to leave in the old position, do it
522 // this is only relevent for riding entities, not pushed
523 // FIXME: this doesn't acount for rotation
524 VectorSubtract (check->s.origin, move, check->s.origin);
525 block = SV_TestEntityPosition (check);
526 if (!block)
527 {
528 pushed_p--;
529 continue;
530 }
531 }
532
533 // save off the obstacle so we can call the block function
534 obstacle = check;
535
536 // move back any entities we already moved
537 // go backwards, so if the same entity was pushed
538 // twice, it goes back to the original position
539 for (p=pushed_p-1 ; p>=pushed ; p--)
540 {
541 VectorCopy (p->origin, p->ent->s.origin);
542 VectorCopy (p->angles, p->ent->s.angles);
543 if (p->ent->client)
544 {
545 p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw;
546 }
547 gi.linkentity (p->ent);
548 }
549 return false;
550 }
551
552 //FIXME: is there a better way to handle this?
553 // see if anything we moved has touched a trigger
554 for (p=pushed_p-1 ; p>=pushed ; p--)
555 G_TouchTriggers (p->ent);
556
557 return true;
558 }
559
560 /*
561 ================
562 SV_Physics_Pusher
563
564 Bmodel objects don't interact with each other, but
565 push all box objects
566 ================
567 */
SV_Physics_Pusher(edict_t * ent)568 void SV_Physics_Pusher (edict_t *ent)
569 {
570 vec3_t move, amove;
571 edict_t *part, *mv;
572
573 // if not a team captain, so movement will be handled elsewhere
574 if ( ent->flags & FL_TEAMSLAVE)
575 return;
576
577 // make sure all team slaves can move before commiting
578 // any moves or calling any think functions
579 // if the move is blocked, all moved objects will be backed out
580 //retry:
581 pushed_p = pushed;
582 for (part = ent ; part ; part=part->teamchain)
583 {
584 if (part->velocity[0] || part->velocity[1] || part->velocity[2] ||
585 part->avelocity[0] || part->avelocity[1] || part->avelocity[2]
586 )
587 { // object is moving
588 VectorScale (part->velocity, FRAMETIME, move);
589 VectorScale (part->avelocity, FRAMETIME, amove);
590
591 if (!SV_Push (part, move, amove))
592 break; // move was blocked
593 }
594 }
595 if (pushed_p > &pushed[MAX_EDICTS])
596 gi.error (ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted");
597
598 if (part)
599 {
600 // the move failed, bump all nextthink times and back out moves
601 for (mv = ent ; mv ; mv=mv->teamchain)
602 {
603 if (mv->nextthink > 0)
604 mv->nextthink += FRAMETIME;
605 }
606
607 // if the pusher has a "blocked" function, call it
608 // otherwise, just stay in place until the obstacle is gone
609 if (part->blocked)
610 part->blocked (part, obstacle);
611 #if 0
612 // if the pushed entity went away and the pusher is still there
613 if (!obstacle->inuse && part->inuse)
614 goto retry;
615 #endif
616 }
617 else
618 {
619 // the move succeeded, so call all think functions
620 for (part = ent ; part ; part=part->teamchain)
621 {
622 SV_RunThink (part);
623 }
624 }
625 }
626
627 //==================================================================
628
629 /*
630 =============
631 SV_Physics_None
632
633 Non moving objects can only think
634 =============
635 */
SV_Physics_None(edict_t * ent)636 void SV_Physics_None (edict_t *ent)
637 {
638 // regular thinking
639 SV_RunThink (ent);
640 }
641
642 /*
643 =============
644 SV_Physics_Noclip
645
646 A moving object that doesn't obey physics
647 =============
648 */
SV_Physics_Noclip(edict_t * ent)649 void SV_Physics_Noclip (edict_t *ent)
650 {
651 // regular thinking
652 if (!SV_RunThink (ent))
653 return;
654
655 VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
656 VectorMA (ent->s.origin, FRAMETIME, ent->velocity, ent->s.origin);
657
658 gi.linkentity (ent);
659 }
660
661 /*
662 ==============================================================================
663
664 TOSS / BOUNCE
665
666 ==============================================================================
667 */
668
669 /*
670 =============
671 SV_Physics_Toss
672
673 Toss, bounce, and fly movement. When onground, do nothing.
674 =============
675 */
SV_Physics_Toss(edict_t * ent)676 void SV_Physics_Toss (edict_t *ent)
677 {
678 trace_t trace;
679 vec3_t move;
680 float backoff;
681 edict_t *slave;
682 qboolean wasinwater;
683 qboolean isinwater;
684 vec3_t old_origin;
685
686 // regular thinking
687 SV_RunThink (ent);
688
689 // if not a team captain, so movement will be handled elsewhere
690 if ( ent->flags & FL_TEAMSLAVE)
691 return;
692
693 if (ent->velocity[2] > 0)
694 ent->groundentity = NULL;
695
696 // check for the groundentity going away
697 if (ent->groundentity)
698 if (!ent->groundentity->inuse)
699 ent->groundentity = NULL;
700
701 // if onground, return without moving
702 if ( ent->groundentity )
703 return;
704
705 VectorCopy (ent->s.origin, old_origin);
706
707 SV_CheckVelocity (ent);
708
709 // add gravity
710 if (ent->movetype != MOVETYPE_FLY
711 && ent->movetype != MOVETYPE_FLYMISSILE)
712 SV_AddGravity (ent);
713
714 // move angles
715 VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
716
717 // move origin
718 VectorScale (ent->velocity, FRAMETIME, move);
719 trace = SV_PushEntity (ent, move);
720 if (!ent->inuse)
721 return;
722
723 if (trace.fraction < 1)
724 {
725 if (ent->movetype == MOVETYPE_BOUNCE)
726 backoff = 1.5;
727 else
728 backoff = 1;
729
730 ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff);
731
732 // stop if on ground
733 if (trace.plane.normal[2] > 0.7)
734 {
735 if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE )
736 {
737 ent->groundentity = trace.ent;
738 ent->groundentity_linkcount = trace.ent->linkcount;
739 VectorCopy (vec3_origin, ent->velocity);
740 VectorCopy (vec3_origin, ent->avelocity);
741 }
742 }
743
744 // if (ent->touch)
745 // ent->touch (ent, trace.ent, &trace.plane, trace.surface);
746 }
747
748 // check for water transition
749 wasinwater = (ent->watertype & MASK_WATER);
750 ent->watertype = gi.pointcontents (ent->s.origin);
751 isinwater = ent->watertype & MASK_WATER;
752
753 if (isinwater)
754 ent->waterlevel = 1;
755 else
756 ent->waterlevel = 0;
757
758 if (!wasinwater && isinwater)
759 gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
760 else if (wasinwater && !isinwater)
761 gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
762
763 // move teamslaves
764 for (slave = ent->teamchain; slave; slave = slave->teamchain)
765 {
766 VectorCopy (ent->s.origin, slave->s.origin);
767 gi.linkentity (slave);
768 }
769 }
770
771 /*
772 ===============================================================================
773
774 STEPPING MOVEMENT
775
776 ===============================================================================
777 */
778
779 /*
780 =============
781 SV_Physics_Step
782
783 Monsters freefall when they don't have a ground entity, otherwise
784 all movement is done with discrete steps.
785
786 This is also used for objects that have become still on the ground, but
787 will fall if the floor is pulled out from under them.
788 FIXME: is this true?
789 =============
790 */
791
792 //FIXME: hacked in for E3 demo
793 #define sv_stopspeed 100
794 #define sv_friction 6
795 #define sv_waterfriction 1
796
SV_AddRotationalFriction(edict_t * ent)797 void SV_AddRotationalFriction (edict_t *ent)
798 {
799 int n;
800 float adjustment;
801
802 VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
803 adjustment = FRAMETIME * sv_stopspeed * sv_friction;
804 for (n = 0; n < 3; n++)
805 {
806 if (ent->avelocity[n] > 0)
807 {
808 ent->avelocity[n] -= adjustment;
809 if (ent->avelocity[n] < 0)
810 ent->avelocity[n] = 0;
811 }
812 else
813 {
814 ent->avelocity[n] += adjustment;
815 if (ent->avelocity[n] > 0)
816 ent->avelocity[n] = 0;
817 }
818 }
819 }
820
SV_Physics_Step(edict_t * ent)821 void SV_Physics_Step (edict_t *ent)
822 {
823 qboolean wasonground;
824 qboolean hitsound = false;
825 float *vel;
826 float speed, newspeed, control;
827 float friction;
828 edict_t *groundentity;
829 int mask;
830
831 // airborn monsters should always check for ground
832 if (!ent->groundentity)
833 M_CheckGround (ent);
834
835 groundentity = ent->groundentity;
836
837 SV_CheckVelocity (ent);
838
839 if (groundentity)
840 wasonground = true;
841 else
842 wasonground = false;
843
844 if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
845 SV_AddRotationalFriction (ent);
846
847 // add gravity except:
848 // flying monsters
849 // swimming monsters who are in the water
850 if (! wasonground)
851 if (!(ent->flags & FL_FLY))
852 if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
853 {
854 if (ent->velocity[2] < sv_gravity->value*-0.1)
855 hitsound = true;
856 if (ent->waterlevel == 0)
857 SV_AddGravity (ent);
858 }
859
860 // friction for flying monsters that have been given vertical velocity
861 if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
862 {
863 speed = fabs(ent->velocity[2]);
864 control = speed < sv_stopspeed ? sv_stopspeed : speed;
865 friction = sv_friction/3;
866 newspeed = speed - (FRAMETIME * control * friction);
867 if (newspeed < 0)
868 newspeed = 0;
869 newspeed /= speed;
870 ent->velocity[2] *= newspeed;
871 }
872
873 // friction for flying monsters that have been given vertical velocity
874 if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
875 {
876 speed = fabs(ent->velocity[2]);
877 control = speed < sv_stopspeed ? sv_stopspeed : speed;
878 newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
879 if (newspeed < 0)
880 newspeed = 0;
881 newspeed /= speed;
882 ent->velocity[2] *= newspeed;
883 }
884
885 if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
886 {
887 // apply friction
888 // let dead monsters who aren't completely onground slide
889 if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
890 if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
891 {
892 vel = ent->velocity;
893 speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
894 if (speed)
895 {
896 friction = sv_friction;
897
898 control = speed < sv_stopspeed ? sv_stopspeed : speed;
899 newspeed = speed - FRAMETIME*control*friction;
900
901 if (newspeed < 0)
902 newspeed = 0;
903 newspeed /= speed;
904
905 vel[0] *= newspeed;
906 vel[1] *= newspeed;
907 }
908 }
909
910 if (ent->svflags & SVF_MONSTER)
911 mask = MASK_MONSTERSOLID;
912 else
913 mask = MASK_SOLID;
914 SV_FlyMove (ent, FRAMETIME, mask);
915
916 gi.linkentity (ent);
917 G_TouchTriggers (ent);
918 if (!ent->inuse)
919 return;
920
921 if (ent->groundentity)
922 if (!wasonground)
923 if (hitsound)
924 gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
925 }
926
927 // regular thinking
928 SV_RunThink (ent);
929 }
930
931 //============================================================================
932 /*
933 ================
934 G_RunEntity
935
936 ================
937 */
G_RunEntity(edict_t * ent)938 void G_RunEntity (edict_t *ent)
939 {
940 if (ent->prethink)
941 ent->prethink (ent);
942
943 switch ( (int)ent->movetype)
944 {
945 case MOVETYPE_PUSH:
946 case MOVETYPE_STOP:
947 SV_Physics_Pusher (ent);
948 break;
949 case MOVETYPE_NONE:
950 SV_Physics_None (ent);
951 break;
952 case MOVETYPE_NOCLIP:
953 SV_Physics_Noclip (ent);
954 break;
955 case MOVETYPE_STEP:
956 SV_Physics_Step (ent);
957 break;
958 case MOVETYPE_TOSS:
959 case MOVETYPE_BOUNCE:
960 case MOVETYPE_FLY:
961 case MOVETYPE_FLYMISSILE:
962 SV_Physics_Toss (ent);
963 break;
964 default:
965 gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype);
966 }
967 }
968