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