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
55 if (ent->clipmask)
56 mask = ent->clipmask;
57 else
58 mask = MASK_SOLID;
59 trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, mask);
60
61 if (trace.startsolid)
62 return g_edicts;
63
64 return NULL;
65 }
66
67
68 /*
69 ================
70 SV_CheckVelocity
71 ================
72 */
SV_CheckVelocity(edict_t * ent)73 void SV_CheckVelocity (edict_t *ent)
74 {
75 int i;
76
77 //
78 // bound velocity
79 //
80 for (i=0 ; i<3 ; i++)
81 {
82 if (ent->velocity[i] > sv_maxvelocity->value)
83 ent->velocity[i] = sv_maxvelocity->value;
84 else if (ent->velocity[i] < -sv_maxvelocity->value)
85 ent->velocity[i] = -sv_maxvelocity->value;
86 }
87 }
88
89 /*
90 =============
91 SV_RunThink
92
93 Runs thinking code for this frame if necessary
94 =============
95 */
SV_RunThink(edict_t * ent)96 qboolean SV_RunThink (edict_t *ent)
97 {
98 float thinktime;
99
100 thinktime = ent->nextthink;
101 if (thinktime <= 0)
102 return true;
103 if (thinktime > level.time+0.001)
104 return true;
105
106 ent->nextthink = 0;
107 if (!ent->think)
108 gi.error ("NULL ent->think");
109 ent->think (ent);
110
111 return false;
112 }
113
114 /*
115 ==================
116 SV_Impact
117
118 Two entities have touched, so run their touch functions
119 ==================
120 */
SV_Impact(edict_t * e1,trace_t * trace)121 void SV_Impact (edict_t *e1, trace_t *trace)
122 {
123 edict_t *e2;
124 // cplane_t backplane;
125
126 e2 = trace->ent;
127
128 if (e1->touch && e1->solid != SOLID_NOT)
129 e1->touch (e1, e2, &trace->plane, trace->surface);
130
131 if (e2->touch && e2->solid != SOLID_NOT)
132 e2->touch (e2, e1, NULL, NULL);
133 }
134
135
136 /*
137 ==================
138 ClipVelocity
139
140 Slide off of the impacting object
141 returns the blocked flags (1 = floor, 2 = step / wall)
142 ==================
143 */
144 #define STOP_EPSILON 0.1
145
ClipVelocity(vec3_t in,vec3_t normal,vec3_t out,float overbounce)146 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
147 {
148 float backoff;
149 float change;
150 int i, blocked;
151
152 blocked = 0;
153 if (normal[2] > 0)
154 blocked |= 1; // floor
155 if (!normal[2])
156 blocked |= 2; // step
157
158 backoff = DotProduct (in, normal) * overbounce;
159
160 for (i=0 ; i<3 ; i++)
161 {
162 change = normal[i]*backoff;
163 out[i] = in[i] - change;
164 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
165 out[i] = 0;
166 }
167
168 return blocked;
169 }
170
171
172 /*
173 ============
174 SV_FlyMove
175
176 The basic solid body movement clip that slides along multiple planes
177 Returns the clipflags if the velocity was modified (hit something solid)
178 1 = floor
179 2 = wall / step
180 4 = dead stop
181 ============
182 */
183 #define MAX_CLIP_PLANES 5
SV_FlyMove(edict_t * ent,float time,int mask)184 int SV_FlyMove (edict_t *ent, float time, int mask)
185 {
186 edict_t *hit;
187 int bumpcount, numbumps;
188 vec3_t dir;
189 float d;
190 int numplanes;
191 vec3_t planes[MAX_CLIP_PLANES];
192 vec3_t primal_velocity, original_velocity, new_velocity;
193 int i, j;
194 trace_t trace;
195 vec3_t end;
196 float time_left;
197 int blocked;
198
199 numbumps = 4;
200
201 blocked = 0;
202 VectorCopy (ent->velocity, original_velocity);
203 VectorCopy (ent->velocity, primal_velocity);
204 numplanes = 0;
205
206 time_left = time;
207
208 ent->groundentity = NULL;
209 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
210 {
211 for (i=0 ; i<3 ; i++)
212 end[i] = ent->s.origin[i] + time_left * ent->velocity[i];
213
214 trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask);
215
216 if (trace.allsolid)
217 { // entity is trapped in another solid
218 VectorCopy (vec3_origin, ent->velocity);
219 return 3;
220 }
221
222 if (trace.fraction > 0)
223 { // actually covered some distance
224 VectorCopy (trace.endpos, ent->s.origin);
225 VectorCopy (ent->velocity, original_velocity);
226 numplanes = 0;
227 }
228
229 if (trace.fraction == 1)
230 break; // moved the entire distance
231
232 hit = trace.ent;
233
234 if (trace.plane.normal[2] > 0.7)
235 {
236 blocked |= 1; // floor
237 if ( hit->solid == SOLID_BSP)
238 {
239 ent->groundentity = hit;
240 ent->groundentity_linkcount = hit->linkcount;
241 }
242 }
243 if (!trace.plane.normal[2])
244 {
245 blocked |= 2; // step
246 }
247
248 //
249 // run the impact function
250 //
251 SV_Impact (ent, &trace);
252 if (!ent->inuse)
253 break; // removed by the impact function
254
255
256 time_left -= time_left * trace.fraction;
257
258 // cliped to another plane
259 if (numplanes >= MAX_CLIP_PLANES)
260 { // this shouldn't really happen
261 VectorCopy (vec3_origin, ent->velocity);
262 return 3;
263 }
264
265 VectorCopy (trace.plane.normal, planes[numplanes]);
266 numplanes++;
267
268 //
269 // modify original_velocity so it parallels all of the clip planes
270 //
271 for (i=0 ; i<numplanes ; i++)
272 {
273 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
274 for (j=0 ; j<numplanes ; j++)
275 if (j != i)
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 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 {
386 edict_t *ent;
387 vec3_t origin;
388 vec3_t angles;
389 float deltayaw;
390 } pushed_t;
391 pushed_t pushed[MAX_EDICTS], *pushed_p;
392
393 edict_t *obstacle;
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 */
SV_Push(edict_t * pusher,vec3_t move,vec3_t amove)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)
440 pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW];
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 {
539 p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw;
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 */
SV_Physics_Pusher(edict_t * ent)562 void SV_Physics_Pusher (edict_t *ent)
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 */
SV_Physics_None(edict_t * ent)630 void SV_Physics_None (edict_t *ent)
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 */
SV_Physics_Noclip(edict_t * ent)643 void SV_Physics_Noclip (edict_t *ent)
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 */
SV_Physics_Toss(edict_t * ent)670 void SV_Physics_Toss (edict_t *ent)
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;
733 VectorCopy (vec3_origin, ent->velocity);
734 VectorCopy (vec3_origin, ent->avelocity);
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
SV_AddRotationalFriction(edict_t * ent)791 void SV_AddRotationalFriction (edict_t *ent)
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
SV_Physics_Step(edict_t * ent)815 void SV_Physics_Step (edict_t *ent)
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])
839 SV_AddRotationalFriction (ent);
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)
905 mask = MASK_MONSTERSOLID;
906 else
907 mask = MASK_SOLID;
908 SV_FlyMove (ent, FRAMETIME, mask);
909
910 gi.linkentity (ent);
911 G_TouchTriggers (ent);
912
913 if (ent->groundentity)
914 if (!wasonground)
915 if (hitsound)
916 gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
917 }
918
919 // regular thinking
920 SV_RunThink (ent);
921 }
922
923 //============================================================================
924 /*
925 ================
926 G_RunEntity
927
928 ================
929 */
G_RunEntity(edict_t * ent)930 void G_RunEntity (edict_t *ent)
931 {
932 if (ent->prethink)
933 ent->prethink (ent);
934
935 switch ( (int)ent->movetype)
936 {
937 case MOVETYPE_PUSH:
938 case MOVETYPE_STOP:
939 SV_Physics_Pusher (ent);
940 break;
941 case MOVETYPE_NONE:
942 SV_Physics_None (ent);
943 break;
944 case MOVETYPE_NOCLIP:
945 SV_Physics_Noclip (ent);
946 break;
947 case MOVETYPE_STEP:
948 SV_Physics_Step (ent);
949 break;
950 case MOVETYPE_TOSS:
951 case MOVETYPE_BOUNCE:
952 case MOVETYPE_FLY:
953 case MOVETYPE_FLYMISSILE:
954 SV_Physics_Toss (ent);
955 break;
956 default:
957 gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype);
958 }
959 }
960