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