|
|
1.1 root 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: */
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: */
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: */
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: */
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:
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
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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:
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:
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: */
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: */
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: //============
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.