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