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 // RAFAEL
688 // move type for rippergun projectile
689 && ent->movetype != MOVETYPE_WALLBOUNCE)
690 SV_AddGravity (ent);
691
692 // move angles
693 VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
694
695 // move origin
696 VectorScale (ent->velocity, FRAMETIME, move);
697 trace = SV_PushEntity (ent, move);
698 if (!ent->inuse)
699 return;
700
701 if (trace.fraction < 1)
702 {
703 // RAFAEL
704 if (ent->movetype == MOVETYPE_WALLBOUNCE)
705 backoff = 2.0;
706 // RAFAEL ( else )
707 else if (ent->movetype == MOVETYPE_BOUNCE)
708 backoff = 1.5;
709 else
710 backoff = 1;
711
712 ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff);
713
714 // RAFAEL
715 if (ent->movetype == MOVETYPE_WALLBOUNCE)
716 vectoangles (ent->velocity, ent->s.angles);
717
718 // stop if on ground
719 // RAFAEL
720 if (trace.plane.normal[2] > 0.7 && ent->movetype != MOVETYPE_WALLBOUNCE)
721 {
722 if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE )
723 {
724 ent->groundentity = trace.ent;
725 ent->groundentity_linkcount = trace.ent->linkcount;
726 VectorCopy (vec3_origin, ent->velocity);
727 VectorCopy (vec3_origin, ent->avelocity);
728 }
729 }
730
731 // if (ent->touch)
732 // ent->touch (ent, trace.ent, &trace.plane, trace.surface);
733 }
734
735 // check for water transition
736 wasinwater = (ent->watertype & MASK_WATER);
737 ent->watertype = gi.pointcontents (ent->s.origin);
738 isinwater = ent->watertype & MASK_WATER;
739
740 if (isinwater)
741 ent->waterlevel = 1;
742 else
743 ent->waterlevel = 0;
744
745 if (!wasinwater && isinwater)
746 gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
747 else if (wasinwater && !isinwater)
748 gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
749
750 // move teamslaves
751 for (slave = ent->teamchain; slave; slave = slave->teamchain)
752 {
753 VectorCopy (ent->s.origin, slave->s.origin);
754 gi.linkentity (slave);
755 }
756 }
757
758 /*
759 ===============================================================================
760
761 STEPPING MOVEMENT
762
763 ===============================================================================
764 */
765
766 /*
767 =============
768 SV_Physics_Step
769
770 Monsters freefall when they don't have a ground entity, otherwise
771 all movement is done with discrete steps.
772
773 This is also used for objects that have become still on the ground, but
774 will fall if the floor is pulled out from under them.
775 FIXME: is this true?
776 =============
777 */
778
779 //FIXME: hacked in for E3 demo
780 #define sv_stopspeed 100
781 #define sv_friction 6
782 #define sv_waterfriction 1
783
SV_AddRotationalFriction(edict_t * ent)784 void SV_AddRotationalFriction (edict_t *ent)
785 {
786 int n;
787 float adjustment;
788
789 VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
790 adjustment = FRAMETIME * sv_stopspeed * sv_friction;
791 for (n = 0; n < 3; n++)
792 {
793 if (ent->avelocity[n] > 0)
794 {
795 ent->avelocity[n] -= adjustment;
796 if (ent->avelocity[n] < 0)
797 ent->avelocity[n] = 0;
798 }
799 else
800 {
801 ent->avelocity[n] += adjustment;
802 if (ent->avelocity[n] > 0)
803 ent->avelocity[n] = 0;
804 }
805 }
806 }
807
SV_Physics_Step(edict_t * ent)808 void SV_Physics_Step (edict_t *ent)
809 {
810 qboolean wasonground;
811 qboolean hitsound = false;
812 float *vel;
813 float speed, newspeed, control;
814 float friction;
815 edict_t *groundentity;
816 int mask;
817
818 // airborn monsters should always check for ground
819 if (!ent->groundentity)
820 M_CheckGround (ent);
821
822 groundentity = ent->groundentity;
823
824 SV_CheckVelocity (ent);
825
826 if (groundentity)
827 wasonground = true;
828 else
829 wasonground = false;
830
831 if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
832 SV_AddRotationalFriction (ent);
833
834 // add gravity except:
835 // flying monsters
836 // swimming monsters who are in the water
837 if (! wasonground)
838 if (!(ent->flags & FL_FLY))
839 if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
840 {
841 if (ent->velocity[2] < sv_gravity->value*-0.1)
842 hitsound = true;
843 if (ent->waterlevel == 0)
844 SV_AddGravity (ent);
845 }
846
847 // friction for flying monsters that have been given vertical velocity
848 if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
849 {
850 speed = fabs(ent->velocity[2]);
851 control = speed < sv_stopspeed ? sv_stopspeed : speed;
852 friction = sv_friction/3;
853 newspeed = speed - (FRAMETIME * control * friction);
854 if (newspeed < 0)
855 newspeed = 0;
856 newspeed /= speed;
857 ent->velocity[2] *= newspeed;
858 }
859
860 // friction for flying monsters that have been given vertical velocity
861 if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
862 {
863 speed = fabs(ent->velocity[2]);
864 control = speed < sv_stopspeed ? sv_stopspeed : speed;
865 newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
866 if (newspeed < 0)
867 newspeed = 0;
868 newspeed /= speed;
869 ent->velocity[2] *= newspeed;
870 }
871
872 if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
873 {
874 // apply friction
875 // let dead monsters who aren't completely onground slide
876 if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
877 if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
878 {
879 vel = ent->velocity;
880 speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
881 if (speed)
882 {
883 friction = sv_friction;
884
885 control = speed < sv_stopspeed ? sv_stopspeed : speed;
886 newspeed = speed - FRAMETIME*control*friction;
887
888 if (newspeed < 0)
889 newspeed = 0;
890 newspeed /= speed;
891
892 vel[0] *= newspeed;
893 vel[1] *= newspeed;
894 }
895 }
896
897 if (ent->svflags & SVF_MONSTER)
898 mask = MASK_MONSTERSOLID;
899 else
900 mask = MASK_SOLID;
901 SV_FlyMove (ent, FRAMETIME, mask);
902
903 gi.linkentity (ent);
904 G_TouchTriggers (ent);
905 if (!ent->inuse)
906 return;
907
908 if (ent->groundentity)
909 if (!wasonground)
910 if (hitsound)
911 gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
912 }
913
914 // regular thinking
915 SV_RunThink (ent);
916 }
917
918 //============================================================================
919 /*
920 ================
921 G_RunEntity
922
923 ================
924 */
G_RunEntity(edict_t * ent)925 void G_RunEntity (edict_t *ent)
926 {
927 if (ent->prethink)
928 ent->prethink (ent);
929
930 switch ( (int)ent->movetype)
931 {
932 #ifdef WITH_ACEBOT
933 // ACEBOT_ADD
934 case MOVETYPE_WALK:
935 SV_RunThink (ent);
936 break;
937 // ACEBOT_END
938 #endif
939 case MOVETYPE_PUSH:
940 case MOVETYPE_STOP:
941 SV_Physics_Pusher (ent);
942 break;
943 case MOVETYPE_NONE:
944 SV_Physics_None (ent);
945 break;
946 case MOVETYPE_NOCLIP:
947 SV_Physics_Noclip (ent);
948 break;
949 case MOVETYPE_STEP:
950 SV_Physics_Step (ent);
951 break;
952 case MOVETYPE_TOSS:
953 case MOVETYPE_BOUNCE:
954 case MOVETYPE_FLY:
955 case MOVETYPE_FLYMISSILE:
956 // RAFAEL
957 case MOVETYPE_WALLBOUNCE:
958 SV_Physics_Toss (ent);
959 break;
960 default:
961 gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype);
962 }
963 }
964