|
|
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:
24: /*
25: ============
26: SV_TestEntityPosition
27:
28: ============
29: */
30: edict_t *SV_TestEntityPosition (edict_t *ent)
31: {
32: trace_t trace;
33: int mask;
34:
35:
36: if (ent->clipmask)
37: mask = ent->clipmask;
38: else
39: mask = MASK_SOLID;
40: trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, mask);
41:
42: if (trace.startsolid)
43: return g_edicts;
44:
45: return NULL;
46: }
47:
48:
49: /*
50: ================
51: SV_CheckVelocity
52: ================
53: */
54: void SV_CheckVelocity (edict_t *ent)
55: {
56: int i;
57:
58: //
59: // bound velocity
60: //
61: for (i=0 ; i<3 ; i++)
62: {
63: if (ent->velocity[i] > sv_maxvelocity->value)
64: ent->velocity[i] = sv_maxvelocity->value;
65: else if (ent->velocity[i] < -sv_maxvelocity->value)
66: ent->velocity[i] = -sv_maxvelocity->value;
67: }
68: }
69:
70: /*
71: =============
72: SV_RunThink
73:
74: Runs thinking code for this frame if necessary
75: =============
76: */
77: qboolean SV_RunThink (edict_t *ent)
78: {
79: float thinktime;
80:
81: thinktime = ent->nextthink;
82: if (thinktime <= 0)
83: return true;
84: if (thinktime > level.time+0.001)
85: return true;
86:
87: ent->nextthink = 0;
88: if (!ent->think)
89: gi.error ("NULL ent->think");
90: ent->think (ent);
91:
92: return false;
93: }
94:
95: /*
96: ==================
97: SV_Impact
98:
99: Two entities have touched, so run their touch functions
100: ==================
101: */
102: void SV_Impact (edict_t *e1, trace_t *trace)
103: {
104: edict_t *e2;
105: // cplane_t backplane;
106:
107: e2 = trace->ent;
108:
109: if (e1->touch && e1->solid != SOLID_NOT)
110: e1->touch (e1, e2, &trace->plane, trace->surface);
111:
112: if (e2->touch && e2->solid != SOLID_NOT)
113: e2->touch (e2, e1, NULL, NULL);
114: }
115:
116:
117: /*
118: ==================
119: ClipVelocity
120:
121: Slide off of the impacting object
122: returns the blocked flags (1 = floor, 2 = step / wall)
123: ==================
124: */
125: #define STOP_EPSILON 0.1
126:
127: int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
128: {
129: float backoff;
130: float change;
131: int i, blocked;
132:
133: blocked = 0;
134: if (normal[2] > 0)
135: blocked |= 1; // floor
136: if (!normal[2])
137: blocked |= 2; // step
138:
139: backoff = DotProduct (in, normal) * overbounce;
140:
141: for (i=0 ; i<3 ; i++)
142: {
143: change = normal[i]*backoff;
144: out[i] = in[i] - change;
145: if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
146: out[i] = 0;
147: }
148:
149: return blocked;
150: }
151:
152:
153: /*
154: ============
155: SV_FlyMove
156:
157: The basic solid body movement clip that slides along multiple planes
158: Returns the clipflags if the velocity was modified (hit something solid)
159: 1 = floor
160: 2 = wall / step
161: 4 = dead stop
162: ============
163: */
164: #define MAX_CLIP_PLANES 5
165: int SV_FlyMove (edict_t *ent, float time, int mask)
166: {
167: edict_t *hit;
168: int bumpcount, numbumps;
169: vec3_t dir;
170: float d;
171: int numplanes;
172: vec3_t planes[MAX_CLIP_PLANES];
173: vec3_t primal_velocity, original_velocity, new_velocity;
174: int i, j;
175: trace_t trace;
176: vec3_t end;
177: float time_left;
178: int blocked;
179:
180: numbumps = 4;
181:
182: blocked = 0;
183: VectorCopy (ent->velocity, original_velocity);
184: VectorCopy (ent->velocity, primal_velocity);
185: numplanes = 0;
186:
187: time_left = time;
188:
189: ent->groundentity = NULL;
190: for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
191: {
192: for (i=0 ; i<3 ; i++)
193: end[i] = ent->s.origin[i] + time_left * ent->velocity[i];
194:
195: trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask);
196:
197: if (trace.allsolid)
198: { // entity is trapped in another solid
199: VectorCopy (vec3_origin, ent->velocity);
200: return 3;
201: }
202:
203: if (trace.fraction > 0)
204: { // actually covered some distance
205: VectorCopy (trace.endpos, ent->s.origin);
206: VectorCopy (ent->velocity, original_velocity);
207: numplanes = 0;
208: }
209:
210: if (trace.fraction == 1)
211: break; // moved the entire distance
212:
213: hit = trace.ent;
214:
215: if (trace.plane.normal[2] > 0.7)
216: {
217: blocked |= 1; // floor
218: if ( hit->solid == SOLID_BSP)
219: {
220: ent->groundentity = hit;
221: ent->groundentity_linkcount = hit->linkcount;
222: }
223: }
224: if (!trace.plane.normal[2])
225: {
226: blocked |= 2; // step
227: }
228:
229: //
230: // run the impact function
231: //
232: SV_Impact (ent, &trace);
233: if (!ent->inuse)
234: break; // removed by the impact function
235:
236:
237: time_left -= time_left * trace.fraction;
238:
239: // cliped to another plane
240: if (numplanes >= MAX_CLIP_PLANES)
241: { // this shouldn't really happen
242: VectorCopy (vec3_origin, ent->velocity);
243: return 3;
244: }
245:
246: VectorCopy (trace.plane.normal, planes[numplanes]);
247: numplanes++;
248:
249: //
250: // modify original_velocity so it parallels all of the clip planes
251: //
252: for (i=0 ; i<numplanes ; i++)
253: {
254: ClipVelocity (original_velocity, planes[i], new_velocity, 1);
255: for (j=0 ; j<numplanes ; j++)
256: if (j != i)
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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: SV_AddGravity (ent);
688:
689: // move angles
690: VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
691:
692: // move origin
693: VectorScale (ent->velocity, FRAMETIME, move);
694: trace = SV_PushEntity (ent, move);
695: if (!ent->inuse)
696: return;
697:
698: if (trace.fraction < 1)
699: {
700: if (ent->movetype == MOVETYPE_BOUNCE)
701: backoff = 1.5;
702: else
703: backoff = 1;
704:
705: ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff);
706:
707: // stop if on ground
708: if (trace.plane.normal[2] > 0.7)
709: {
710: if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE )
711: {
712: ent->groundentity = trace.ent;
713: ent->groundentity_linkcount = trace.ent->linkcount;
714: VectorCopy (vec3_origin, ent->velocity);
715: VectorCopy (vec3_origin, ent->avelocity);
716: }
717: }
718:
719: // if (ent->touch)
720: // ent->touch (ent, trace.ent, &trace.plane, trace.surface);
721: }
722:
723: // check for water transition
724: wasinwater = (ent->watertype & MASK_WATER);
725: ent->watertype = gi.pointcontents (ent->s.origin);
726: isinwater = ent->watertype & MASK_WATER;
727:
728: if (isinwater)
729: ent->waterlevel = 1;
730: else
731: ent->waterlevel = 0;
732:
733: if (!wasinwater && isinwater)
734: gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
735: else if (wasinwater && !isinwater)
736: gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
737:
738: // move teamslaves
739: for (slave = ent->teamchain; slave; slave = slave->teamchain)
740: {
741: VectorCopy (ent->s.origin, slave->s.origin);
742: gi.linkentity (slave);
743: }
744: }
745:
746: /*
747: ===============================================================================
748:
749: STEPPING MOVEMENT
750:
751: ===============================================================================
752: */
753:
754: /*
755: =============
756: SV_Physics_Step
757:
758: Monsters freefall when they don't have a ground entity, otherwise
759: all movement is done with discrete steps.
760:
761: This is also used for objects that have become still on the ground, but
762: will fall if the floor is pulled out from under them.
763: FIXME: is this true?
764: =============
765: */
766:
767: //FIXME: hacked in for E3 demo
768: #define sv_stopspeed 100
769: #define sv_friction 6
770: #define sv_waterfriction 1
771:
772: void SV_AddRotationalFriction (edict_t *ent)
773: {
774: int n;
775: float adjustment;
776:
777: VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
778: adjustment = FRAMETIME * sv_stopspeed * sv_friction;
779: for (n = 0; n < 3; n++)
780: {
781: if (ent->avelocity[n] > 0)
782: {
783: ent->avelocity[n] -= adjustment;
784: if (ent->avelocity[n] < 0)
785: ent->avelocity[n] = 0;
786: }
787: else
788: {
789: ent->avelocity[n] += adjustment;
790: if (ent->avelocity[n] > 0)
791: ent->avelocity[n] = 0;
792: }
793: }
794: }
795:
796: void SV_Physics_Step (edict_t *ent)
797: {
798: qboolean wasonground;
799: qboolean hitsound = false;
800: float *vel;
801: float speed, newspeed, control;
802: float friction;
803: edict_t *groundentity;
804: int mask;
805:
806: // airborn monsters should always check for ground
807: if (!ent->groundentity)
808: M_CheckGround (ent);
809:
810: groundentity = ent->groundentity;
811:
812: SV_CheckVelocity (ent);
813:
814: if (groundentity)
815: wasonground = true;
816: else
817: wasonground = false;
818:
819: if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
820: SV_AddRotationalFriction (ent);
821:
822: // add gravity except:
823: // flying monsters
824: // swimming monsters who are in the water
825: if (! wasonground)
826: if (!(ent->flags & FL_FLY))
827: if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
828: {
829: if (ent->velocity[2] < sv_gravity->value*-0.1)
830: hitsound = true;
831: if (ent->waterlevel == 0)
832: SV_AddGravity (ent);
833: }
834:
835: // friction for flying monsters that have been given vertical velocity
836: if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
837: {
838: speed = fabs(ent->velocity[2]);
839: control = speed < sv_stopspeed ? sv_stopspeed : speed;
840: friction = sv_friction/3;
841: newspeed = speed - (FRAMETIME * control * friction);
842: if (newspeed < 0)
843: newspeed = 0;
844: newspeed /= speed;
845: ent->velocity[2] *= newspeed;
846: }
847:
848: // friction for flying monsters that have been given vertical velocity
849: if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
850: {
851: speed = fabs(ent->velocity[2]);
852: control = speed < sv_stopspeed ? sv_stopspeed : speed;
853: newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
854: if (newspeed < 0)
855: newspeed = 0;
856: newspeed /= speed;
857: ent->velocity[2] *= newspeed;
858: }
859:
860: if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
861: {
862: // apply friction
863: // let dead monsters who aren't completely onground slide
864: if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
865: if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
866: {
867: vel = ent->velocity;
868: speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
869: if (speed)
870: {
871: friction = sv_friction;
872:
873: control = speed < sv_stopspeed ? sv_stopspeed : speed;
874: newspeed = speed - FRAMETIME*control*friction;
875:
876: if (newspeed < 0)
877: newspeed = 0;
878: newspeed /= speed;
879:
880: vel[0] *= newspeed;
881: vel[1] *= newspeed;
882: }
883: }
884:
885: if (ent->svflags & SVF_MONSTER)
886: mask = MASK_MONSTERSOLID;
887: else
888: mask = MASK_SOLID;
889: SV_FlyMove (ent, FRAMETIME, mask);
890:
891: gi.linkentity (ent);
892: G_TouchTriggers (ent);
893:
894: if (ent->groundentity)
895: if (!wasonground)
896: if (hitsound)
897: gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
898: }
899:
900: // regular thinking
901: SV_RunThink (ent);
902: }
903:
904: //============================================================================
905: /*
906: ================
907: G_RunEntity
908:
909: ================
910: */
911: void G_RunEntity (edict_t *ent)
912: {
913: if (ent->prethink)
914: ent->prethink (ent);
915:
916: switch ( (int)ent->movetype)
917: {
918: case MOVETYPE_PUSH:
919: case MOVETYPE_STOP:
920: SV_Physics_Pusher (ent);
921: break;
922: case MOVETYPE_NONE:
923: SV_Physics_None (ent);
924: break;
925: case MOVETYPE_NOCLIP:
926: SV_Physics_Noclip (ent);
927: break;
928: case MOVETYPE_STEP:
929: SV_Physics_Step (ent);
930: break;
931: case MOVETYPE_TOSS:
932: case MOVETYPE_BOUNCE:
933: case MOVETYPE_FLY:
934: case MOVETYPE_FLYMISSILE:
935: SV_Physics_Toss (ent);
936: break;
937: default:
938: gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype);
939: }
940: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.