|
|
1.1 root 1:
2: #include "qcommon.h"
3:
1.1.1.2 root 4:
5:
1.1 root 6: #define STEPSIZE 18
7:
8: // all of the locals will be zeroed before each
9: // pmove, just to make damn sure we don't have
10: // any differences when running on client or server
11:
12: typedef struct
13: {
14: vec3_t origin; // full float precision
15: vec3_t velocity; // full float precision
16:
17: vec3_t forward, right, up;
18: float frametime;
19:
20:
21: csurface_t *groundsurface;
22: cplane_t groundplane;
23: int groundcontents;
24:
25: vec3_t previous_origin;
26: qboolean ladder;
27: } pml_t;
28:
29: pmove_t *pm;
30: pml_t pml;
31:
1.1.1.2 root 32:
1.1 root 33: // movement parameters
34: float pm_stopspeed = 100;
35: float pm_maxspeed = 300;
36: float pm_duckspeed = 100;
37: float pm_accelerate = 10;
1.1.1.3 ! root 38: float pm_airaccelerate = 0;
1.1 root 39: float pm_wateraccelerate = 10;
40: float pm_friction = 6;
41: float pm_waterfriction = 1;
42: float pm_waterspeed = 400;
1.1.1.2 root 43:
1.1 root 44: /*
1.1.1.2 root 45:
1.1 root 46: walking up a step should kill some velocity
1.1.1.2 root 47:
1.1 root 48: */
1.1.1.2 root 49:
50:
1.1 root 51: /*
52: ==================
53: PM_ClipVelocity
1.1.1.2 root 54:
1.1 root 55: Slide off of the impacting object
56: returns the blocked flags (1 = floor, 2 = step / wall)
57: ==================
58: */
59: #define STOP_EPSILON 0.1
1.1.1.2 root 60:
1.1 root 61: void PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
62: {
63: float backoff;
64: float change;
65: int i;
66:
67: backoff = DotProduct (in, normal) * overbounce;
1.1.1.2 root 68:
1.1 root 69: for (i=0 ; i<3 ; i++)
70: {
71: change = normal[i]*backoff;
72: out[i] = in[i] - change;
73: if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
74: out[i] = 0;
75: }
76: }
1.1.1.2 root 77:
78:
79:
80:
1.1 root 81: /*
82: ==================
83: PM_StepSlideMove
1.1.1.2 root 84:
1.1 root 85: Each intersection will try to step over the obstruction instead of
86: sliding along it.
1.1.1.2 root 87:
1.1 root 88: Returns a new origin, velocity, and contact entity
89: Does not modify any world state?
90: ==================
91: */
92: #define MIN_STEP_NORMAL 0.7 // can't step up onto very steep slopes
93: #define MAX_CLIP_PLANES 5
94: void PM_StepSlideMove_ (void)
95: {
96: int bumpcount, numbumps;
97: vec3_t dir;
1.1.1.2 root 98: float d;
1.1 root 99: int numplanes;
100: vec3_t planes[MAX_CLIP_PLANES];
101: vec3_t primal_velocity;
1.1.1.2 root 102: int i, j;
1.1 root 103: trace_t trace;
104: vec3_t end;
105: float time_left;
106:
107: numbumps = 4;
108:
109: VectorCopy (pml.velocity, primal_velocity);
110: numplanes = 0;
111:
112: time_left = pml.frametime;
1.1.1.2 root 113:
1.1 root 114: for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
115: {
116: for (i=0 ; i<3 ; i++)
117: end[i] = pml.origin[i] + time_left * pml.velocity[i];
1.1.1.2 root 118:
1.1 root 119: trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
1.1.1.2 root 120:
1.1 root 121: if (trace.allsolid)
122: { // entity is trapped in another solid
123: pml.velocity[2] = 0; // don't build up falling damage
124: return;
125: }
1.1.1.2 root 126:
1.1 root 127: if (trace.fraction > 0)
128: { // actually covered some distance
129: VectorCopy (trace.endpos, pml.origin);
130: numplanes = 0;
131: }
1.1.1.2 root 132:
1.1 root 133: if (trace.fraction == 1)
134: break; // moved the entire distance
1.1.1.2 root 135:
1.1 root 136: // save entity for contact
137: if (pm->numtouch < MAXTOUCH && trace.ent)
138: {
139: pm->touchents[pm->numtouch] = trace.ent;
140: pm->numtouch++;
141: }
142:
143: time_left -= time_left * trace.fraction;
1.1.1.2 root 144:
1.1 root 145: // slide along this plane
146: if (numplanes >= MAX_CLIP_PLANES)
147: { // this shouldn't really happen
148: VectorCopy (vec3_origin, pml.velocity);
149: break;
150: }
1.1.1.2 root 151:
1.1 root 152: VectorCopy (trace.plane.normal, planes[numplanes]);
153: numplanes++;
1.1.1.2 root 154:
155: #if 0
156: float rub;
157:
1.1 root 158: //
159: // modify velocity so it parallels all of the clip planes
160: //
161: if (numplanes == 1)
162: { // go along this plane
163: VectorCopy (pml.velocity, dir);
164: VectorNormalize (dir);
165: rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
166:
167: // slide along the plane
168: PM_ClipVelocity (pml.velocity, planes[0], pml.velocity, 1.01);
169: // rub some extra speed off on xy axis
170: // not on Z, or you can scrub down walls
171: pml.velocity[0] *= rub;
172: pml.velocity[1] *= rub;
173: pml.velocity[2] *= rub;
174: }
175: else if (numplanes == 2)
176: { // go along the crease
177: VectorCopy (pml.velocity, dir);
178: VectorNormalize (dir);
179: rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
180:
181: // slide along the plane
182: CrossProduct (planes[0], planes[1], dir);
183: d = DotProduct (dir, pml.velocity);
184: VectorScale (dir, d, pml.velocity);
1.1.1.2 root 185:
1.1 root 186: // rub some extra speed off
187: VectorScale (pml.velocity, rub, pml.velocity);
188: }
189: else
190: {
191: // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
192: VectorCopy (vec3_origin, pml.velocity);
193: break;
194: }
1.1.1.2 root 195:
196: #else
197: //
198: // modify original_velocity so it parallels all of the clip planes
199: //
200: for (i=0 ; i<numplanes ; i++)
201: {
202: PM_ClipVelocity (pml.velocity, planes[i], pml.velocity, 1.01);
203: for (j=0 ; j<numplanes ; j++)
204: if (j != i)
205: {
206: if (DotProduct (pml.velocity, planes[j]) < 0)
207: break; // not ok
208: }
209: if (j == numplanes)
210: break;
211: }
212:
213: if (i != numplanes)
214: { // go along this plane
215: }
216: else
217: { // go along the crease
218: if (numplanes != 2)
219: {
220: // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
221: VectorCopy (vec3_origin, pml.velocity);
222: break;
223: }
224: CrossProduct (planes[0], planes[1], dir);
225: d = DotProduct (dir, pml.velocity);
226: VectorScale (dir, d, pml.velocity);
227: }
228: #endif
1.1 root 229: //
230: // if velocity is against the original velocity, stop dead
231: // to avoid tiny occilations in sloping corners
232: //
233: if (DotProduct (pml.velocity, primal_velocity) <= 0)
234: {
235: VectorCopy (vec3_origin, pml.velocity);
236: break;
237: }
238: }
1.1.1.2 root 239:
1.1 root 240: if (pm->s.pm_time)
241: {
242: VectorCopy (primal_velocity, pml.velocity);
243: }
244: }
245:
246: /*
247: ==================
248: PM_StepSlideMove
249:
250: ==================
251: */
252: void PM_StepSlideMove (void)
253: {
254: vec3_t start_o, start_v;
255: vec3_t down_o, down_v;
256: trace_t trace;
257: float down_dist, up_dist;
1.1.1.2 root 258: // vec3_t delta;
1.1 root 259: vec3_t up, down;
260:
261: VectorCopy (pml.origin, start_o);
262: VectorCopy (pml.velocity, start_v);
263:
264: PM_StepSlideMove_ ();
265:
266: VectorCopy (pml.origin, down_o);
267: VectorCopy (pml.velocity, down_v);
268:
269: VectorCopy (start_o, up);
270: up[2] += STEPSIZE;
271:
272: trace = pm->trace (up, pm->mins, pm->maxs, up);
273: if (trace.allsolid)
274: return; // can't step up
275:
276: // try sliding above
277: VectorCopy (up, pml.origin);
278: VectorCopy (start_v, pml.velocity);
279:
280: PM_StepSlideMove_ ();
281:
282: // push down the final amount
283: VectorCopy (pml.origin, down);
284: down[2] -= STEPSIZE;
285: trace = pm->trace (pml.origin, pm->mins, pm->maxs, down);
286: if (!trace.allsolid)
287: {
288: VectorCopy (trace.endpos, pml.origin);
289: }
290:
1.1.1.2 root 291: #if 0
1.1 root 292: VectorSubtract (pml.origin, up, delta);
293: up_dist = DotProduct (delta, start_v);
294:
295: VectorSubtract (down_o, start_o, delta);
296: down_dist = DotProduct (delta, start_v);
1.1.1.2 root 297: #else
298: VectorCopy(pml.origin, up);
299:
300: // decide which one went farther
301: down_dist = (down_o[0] - start_o[0])*(down_o[0] - start_o[0])
302: + (down_o[1] - start_o[1])*(down_o[1] - start_o[1]);
303: up_dist = (up[0] - start_o[0])*(up[0] - start_o[0])
304: + (up[1] - start_o[1])*(up[1] - start_o[1]);
305: #endif
1.1 root 306:
307: if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL)
308: {
309: VectorCopy (down_o, pml.origin);
310: VectorCopy (down_v, pml.velocity);
311: return;
312: }
1.1.1.2 root 313: //!! Special case
314: // if we were walking along a plane, then we need to copy the Z over
315: pml.velocity[2] = down_v[2];
1.1 root 316: }
317:
1.1.1.2 root 318:
1.1 root 319: /*
320: ==================
321: PM_Friction
1.1.1.2 root 322:
1.1 root 323: Handles both ground friction and water friction
324: ==================
325: */
326: void PM_Friction (void)
327: {
328: float *vel;
329: float speed, newspeed, control;
330: float friction;
331: float drop;
332:
333: vel = pml.velocity;
334:
335: speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]);
336: if (speed < 1)
337: {
338: vel[0] = 0;
339: vel[1] = 0;
340: return;
341: }
1.1.1.2 root 342:
1.1 root 343: drop = 0;
1.1.1.2 root 344:
1.1 root 345: // apply ground friction
346: if ((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK) ) || (pml.ladder) )
347: {
348: friction = pm_friction;
349: control = speed < pm_stopspeed ? pm_stopspeed : speed;
350: drop += control*friction*pml.frametime;
351: }
1.1.1.2 root 352:
1.1 root 353: // apply water friction
1.1.1.3 ! root 354: if (pm->waterlevel && !pml.ladder)
1.1 root 355: drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;
1.1.1.2 root 356:
1.1 root 357: // scale the velocity
358: newspeed = speed - drop;
359: if (newspeed < 0)
360: {
361: newspeed = 0;
362: }
363: newspeed /= speed;
1.1.1.2 root 364:
1.1 root 365: vel[0] = vel[0] * newspeed;
366: vel[1] = vel[1] * newspeed;
367: vel[2] = vel[2] * newspeed;
368: }
1.1.1.2 root 369:
370:
1.1 root 371: /*
372: ==============
373: PM_Accelerate
1.1.1.2 root 374:
1.1 root 375: Handles user intended acceleration
376: ==============
377: */
378: void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel)
379: {
380: int i;
381: float addspeed, accelspeed, currentspeed;
382:
383: currentspeed = DotProduct (pml.velocity, wishdir);
384: addspeed = wishspeed - currentspeed;
385: if (addspeed <= 0)
386: return;
387: accelspeed = accel*pml.frametime*wishspeed;
388: if (accelspeed > addspeed)
389: accelspeed = addspeed;
390:
391: for (i=0 ; i<3 ; i++)
392: pml.velocity[i] += accelspeed*wishdir[i];
393: }
1.1.1.2 root 394:
395: void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel)
396: {
397: int i;
398: float addspeed, accelspeed, currentspeed, wishspd = wishspeed;
399:
400: if (wishspd > 30)
401: wishspd = 30;
402: currentspeed = DotProduct (pml.velocity, wishdir);
403: addspeed = wishspd - currentspeed;
404: if (addspeed <= 0)
405: return;
406: accelspeed = accel * wishspeed * pml.frametime;
407: if (accelspeed > addspeed)
408: accelspeed = addspeed;
409:
410: for (i=0 ; i<3 ; i++)
411: pml.velocity[i] += accelspeed*wishdir[i];
412: }
413:
1.1 root 414: /*
415: =============
416: PM_AddCurrents
417: =============
418: */
419: void PM_AddCurrents (vec3_t wishvel)
420: {
421: vec3_t v;
422: float s;
1.1.1.2 root 423:
1.1 root 424: //
425: // account for ladders
426: //
1.1.1.2 root 427:
1.1 root 428: if (pml.ladder && fabs(pml.velocity[2]) <= 200)
429: {
430: if ((pm->viewangles[PITCH] <= -15) && (pm->cmd.forwardmove > 0))
431: wishvel[2] = 200;
432: else if ((pm->viewangles[PITCH] >= 15) && (pm->cmd.forwardmove > 0))
433: wishvel[2] = -200;
434: else if (pm->cmd.upmove > 0)
435: wishvel[2] = 200;
436: else if (pm->cmd.upmove < 0)
437: wishvel[2] = -200;
438: else
439: wishvel[2] = 0;
1.1.1.2 root 440:
1.1 root 441: // limit horizontal speed when on a ladder
442: if (wishvel[0] < -25)
443: wishvel[0] = -25;
444: else if (wishvel[0] > 25)
445: wishvel[0] = 25;
1.1.1.2 root 446:
1.1 root 447: if (wishvel[1] < -25)
448: wishvel[1] = -25;
449: else if (wishvel[1] > 25)
450: wishvel[1] = 25;
451: }
1.1.1.2 root 452:
453:
1.1 root 454: //
455: // add water currents
456: //
1.1.1.2 root 457:
1.1 root 458: if (pm->watertype & MASK_CURRENT)
459: {
460: VectorClear (v);
1.1.1.2 root 461:
1.1 root 462: if (pm->watertype & CONTENTS_CURRENT_0)
463: v[0] += 1;
464: if (pm->watertype & CONTENTS_CURRENT_90)
465: v[1] += 1;
466: if (pm->watertype & CONTENTS_CURRENT_180)
467: v[0] -= 1;
468: if (pm->watertype & CONTENTS_CURRENT_270)
469: v[1] -= 1;
470: if (pm->watertype & CONTENTS_CURRENT_UP)
471: v[2] += 1;
472: if (pm->watertype & CONTENTS_CURRENT_DOWN)
473: v[2] -= 1;
1.1.1.2 root 474:
1.1 root 475: s = pm_waterspeed;
476: if ((pm->waterlevel == 1) && (pm->groundentity))
477: s /= 2;
1.1.1.2 root 478:
1.1 root 479: VectorMA (wishvel, s, v, wishvel);
480: }
1.1.1.2 root 481:
1.1 root 482: //
483: // add conveyor belt velocities
484: //
1.1.1.2 root 485:
1.1 root 486: if (pm->groundentity)
487: {
488: VectorClear (v);
1.1.1.2 root 489:
1.1 root 490: if (pml.groundcontents & CONTENTS_CURRENT_0)
491: v[0] += 1;
492: if (pml.groundcontents & CONTENTS_CURRENT_90)
493: v[1] += 1;
494: if (pml.groundcontents & CONTENTS_CURRENT_180)
495: v[0] -= 1;
496: if (pml.groundcontents & CONTENTS_CURRENT_270)
497: v[1] -= 1;
498: if (pml.groundcontents & CONTENTS_CURRENT_UP)
499: v[2] += 1;
500: if (pml.groundcontents & CONTENTS_CURRENT_DOWN)
501: v[2] -= 1;
502:
503: VectorMA (wishvel, 100 /* pm->groundentity->speed */, v, wishvel);
504: }
505: }
1.1.1.2 root 506:
507:
1.1 root 508: /*
509: ===================
510: PM_WaterMove
1.1.1.2 root 511:
1.1 root 512: ===================
513: */
514: void PM_WaterMove (void)
515: {
516: int i;
517: vec3_t wishvel;
518: float wishspeed;
519: vec3_t wishdir;
1.1.1.2 root 520:
1.1 root 521: //
522: // user intentions
523: //
524: for (i=0 ; i<3 ; i++)
525: wishvel[i] = pml.forward[i]*pm->cmd.forwardmove + pml.right[i]*pm->cmd.sidemove;
1.1.1.2 root 526:
1.1 root 527: if (!pm->cmd.forwardmove && !pm->cmd.sidemove && !pm->cmd.upmove)
528: wishvel[2] -= 60; // drift towards bottom
529: else
530: wishvel[2] += pm->cmd.upmove;
1.1.1.2 root 531:
1.1 root 532: PM_AddCurrents (wishvel);
1.1.1.2 root 533:
1.1 root 534: VectorCopy (wishvel, wishdir);
535: wishspeed = VectorNormalize(wishdir);
1.1.1.2 root 536:
1.1 root 537: if (wishspeed > pm_maxspeed)
538: {
539: VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
540: wishspeed = pm_maxspeed;
541: }
542: wishspeed *= 0.5;
1.1.1.2 root 543:
1.1 root 544: PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);
1.1.1.2 root 545:
1.1 root 546: PM_StepSlideMove ();
547: }
1.1.1.2 root 548:
549:
1.1 root 550: /*
551: ===================
552: PM_AirMove
1.1.1.2 root 553:
1.1 root 554: ===================
555: */
556: void PM_AirMove (void)
557: {
558: int i;
559: vec3_t wishvel;
560: float fmove, smove;
561: vec3_t wishdir;
562: float wishspeed;
563: float maxspeed;
1.1.1.2 root 564:
1.1 root 565: fmove = pm->cmd.forwardmove;
566: smove = pm->cmd.sidemove;
567:
1.1.1.2 root 568: //!!!!! pitch should be 1/3 so this isn't needed??!
569: #if 0
1.1 root 570: pml.forward[2] = 0;
571: pml.right[2] = 0;
572: VectorNormalize (pml.forward);
573: VectorNormalize (pml.right);
1.1.1.2 root 574: #endif
575:
1.1 root 576: for (i=0 ; i<2 ; i++)
577: wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
578: wishvel[2] = 0;
1.1.1.2 root 579:
1.1 root 580: PM_AddCurrents (wishvel);
1.1.1.2 root 581:
1.1 root 582: VectorCopy (wishvel, wishdir);
583: wishspeed = VectorNormalize(wishdir);
1.1.1.2 root 584:
1.1 root 585: //
586: // clamp to server defined max speed
587: //
588: maxspeed = (pm->s.pm_flags & PMF_DUCKED) ? pm_duckspeed : pm_maxspeed;
1.1.1.2 root 589:
1.1 root 590: if (wishspeed > maxspeed)
591: {
592: VectorScale (wishvel, maxspeed/wishspeed, wishvel);
593: wishspeed = maxspeed;
594: }
595:
596: if ( pml.ladder )
597: {
598: PM_Accelerate (wishdir, wishspeed, pm_accelerate);
599: if (!wishvel[2])
600: {
601: if (pml.velocity[2] > 0)
602: {
603: pml.velocity[2] -= pm->s.gravity * pml.frametime;
604: if (pml.velocity[2] < 0)
605: pml.velocity[2] = 0;
606: }
607: else
608: {
609: pml.velocity[2] += pm->s.gravity * pml.frametime;
610: if (pml.velocity[2] > 0)
611: pml.velocity[2] = 0;
612: }
613: }
614: PM_StepSlideMove ();
615: }
616: else if ( pm->groundentity )
617: { // walking on ground
1.1.1.2 root 618: pml.velocity[2] = 0; //!!! this is before the accel
1.1 root 619: PM_Accelerate (wishdir, wishspeed, pm_accelerate);
1.1.1.3 ! root 620:
! 621: // PGM -- fix for negative trigger_gravity fields
! 622: // pml.velocity[2] = 0;
! 623: if(pm->s.gravity > 0)
! 624: pml.velocity[2] = 0;
! 625: else
! 626: pml.velocity[2] -= pm->s.gravity * pml.frametime;
! 627: // PGM
! 628:
1.1 root 629: if (!pml.velocity[0] && !pml.velocity[1])
630: return;
631: PM_StepSlideMove ();
632: }
633: else
634: { // not on ground, so little effect on velocity
1.1.1.3 ! root 635: if (pm_airaccelerate)
! 636: PM_AirAccelerate (wishdir, wishspeed, pm_accelerate);
! 637: else
! 638: PM_Accelerate (wishdir, wishspeed, 1);
1.1 root 639: // add gravity
640: pml.velocity[2] -= pm->s.gravity * pml.frametime;
641: PM_StepSlideMove ();
642: }
643: }
1.1.1.2 root 644:
645:
646:
1.1 root 647: /*
648: =============
649: PM_CatagorizePosition
650: =============
651: */
652: void PM_CatagorizePosition (void)
653: {
654: vec3_t point;
655: int cont;
656: trace_t trace;
657: int sample1;
658: int sample2;
1.1.1.2 root 659:
1.1 root 660: // if the player hull point one unit down is solid, the player
661: // is on ground
1.1.1.2 root 662:
1.1 root 663: // see if standing on something solid
664: point[0] = pml.origin[0];
665: point[1] = pml.origin[1];
666: point[2] = pml.origin[2] - 0.25;
1.1.1.2 root 667: if (pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp accel)
1.1 root 668: {
669: pm->s.pm_flags &= ~PMF_ON_GROUND;
670: pm->groundentity = NULL;
671: }
672: else
673: {
674: trace = pm->trace (pml.origin, pm->mins, pm->maxs, point);
675: pml.groundplane = trace.plane;
676: pml.groundsurface = trace.surface;
677: pml.groundcontents = trace.contents;
678:
679: if (!trace.ent || (trace.plane.normal[2] < 0.7 && !trace.startsolid) )
680: {
681: pm->groundentity = NULL;
682: pm->s.pm_flags &= ~PMF_ON_GROUND;
683: }
684: else
685: {
686: pm->groundentity = trace.ent;
687:
688: // hitting solid ground will end a waterjump
689: if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
690: {
691: pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
692: pm->s.pm_time = 0;
693: }
694:
695: if (! (pm->s.pm_flags & PMF_ON_GROUND) )
696: { // just hit the ground
697: pm->s.pm_flags |= PMF_ON_GROUND;
698: // don't do landing time if we were just going down a slope
699: if (pml.velocity[2] < -200)
700: {
701: pm->s.pm_flags |= PMF_TIME_LAND;
702: // don't allow another jump for a little while
703: if (pml.velocity[2] < -400)
704: pm->s.pm_time = 25;
705: else
706: pm->s.pm_time = 18;
707: }
708: }
709: }
1.1.1.2 root 710:
711: #if 0
1.1 root 712: if (trace.fraction < 1.0 && trace.ent && pml.velocity[2] < 0)
713: pml.velocity[2] = 0;
1.1.1.2 root 714: #endif
1.1 root 715:
716: if (pm->numtouch < MAXTOUCH && trace.ent)
717: {
718: pm->touchents[pm->numtouch] = trace.ent;
719: pm->numtouch++;
720: }
721: }
1.1.1.2 root 722:
1.1 root 723: //
724: // get waterlevel, accounting for ducking
725: //
726: pm->waterlevel = 0;
727: pm->watertype = 0;
1.1.1.2 root 728:
1.1 root 729: sample2 = pm->viewheight - pm->mins[2];
730: sample1 = sample2 / 2;
1.1.1.2 root 731:
1.1 root 732: point[2] = pml.origin[2] + pm->mins[2] + 1;
733: cont = pm->pointcontents (point);
1.1.1.2 root 734:
1.1 root 735: if (cont & MASK_WATER)
736: {
737: pm->watertype = cont;
738: pm->waterlevel = 1;
739: point[2] = pml.origin[2] + pm->mins[2] + sample1;
740: cont = pm->pointcontents (point);
741: if (cont & MASK_WATER)
742: {
743: pm->waterlevel = 2;
744: point[2] = pml.origin[2] + pm->mins[2] + sample2;
745: cont = pm->pointcontents (point);
746: if (cont & MASK_WATER)
747: pm->waterlevel = 3;
748: }
749: }
1.1.1.2 root 750:
1.1 root 751: }
1.1.1.2 root 752:
753:
1.1 root 754: /*
755: =============
756: PM_CheckJump
757: =============
758: */
759: void PM_CheckJump (void)
760: {
761: if (pm->s.pm_flags & PMF_TIME_LAND)
762: { // hasn't been long enough since landing to jump again
763: return;
764: }
1.1.1.2 root 765:
1.1 root 766: if (pm->cmd.upmove < 10)
767: { // not holding jump
768: pm->s.pm_flags &= ~PMF_JUMP_HELD;
769: return;
770: }
771:
772: // must wait for jump to be released
773: if (pm->s.pm_flags & PMF_JUMP_HELD)
774: return;
775:
776: if (pm->s.pm_type == PM_DEAD)
777: return;
1.1.1.2 root 778:
1.1 root 779: if (pm->waterlevel >= 2)
780: { // swimming, not jumping
781: pm->groundentity = NULL;
1.1.1.2 root 782:
1.1 root 783: if (pml.velocity[2] <= -300)
784: return;
785:
786: if (pm->watertype == CONTENTS_WATER)
787: pml.velocity[2] = 100;
788: else if (pm->watertype == CONTENTS_SLIME)
789: pml.velocity[2] = 80;
790: else
791: pml.velocity[2] = 50;
792: return;
793: }
1.1.1.2 root 794:
1.1 root 795: if (pm->groundentity == NULL)
796: return; // in air, so no effect
1.1.1.2 root 797:
1.1 root 798: pm->s.pm_flags |= PMF_JUMP_HELD;
799:
800: pm->groundentity = NULL;
1.1.1.2 root 801: pml.velocity[2] += 270;
802: if (pml.velocity[2] < 270)
803: pml.velocity[2] = 270;
1.1 root 804: }
1.1.1.2 root 805:
806:
1.1 root 807: /*
808: =============
809: PM_CheckSpecialMovement
810: =============
811: */
812: void PM_CheckSpecialMovement (void)
813: {
814: vec3_t spot;
815: int cont;
816: vec3_t flatforward;
817: trace_t trace;
818:
819: if (pm->s.pm_time)
820: return;
821:
822: pml.ladder = false;
1.1.1.2 root 823:
1.1 root 824: // check for ladder
825: flatforward[0] = pml.forward[0];
826: flatforward[1] = pml.forward[1];
827: flatforward[2] = 0;
828: VectorNormalize (flatforward);
1.1.1.2 root 829:
1.1 root 830: VectorMA (pml.origin, 1, flatforward, spot);
831: trace = pm->trace (pml.origin, pm->mins, pm->maxs, spot);
832: if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER))
833: pml.ladder = true;
1.1.1.2 root 834:
1.1 root 835: // check for water jump
836: if (pm->waterlevel != 2)
837: return;
1.1.1.2 root 838:
1.1 root 839: VectorMA (pml.origin, 30, flatforward, spot);
840: spot[2] += 4;
841: cont = pm->pointcontents (spot);
842: if (!(cont & CONTENTS_SOLID))
843: return;
1.1.1.2 root 844:
1.1 root 845: spot[2] += 16;
846: cont = pm->pointcontents (spot);
847: if (cont)
848: return;
849: // jump out of water
1.1.1.2 root 850: VectorScale (flatforward, 50, pml.velocity);
1.1 root 851: pml.velocity[2] = 350;
852:
853: pm->s.pm_flags |= PMF_TIME_WATERJUMP;
854: pm->s.pm_time = 255;
855: }
1.1.1.2 root 856:
857:
1.1 root 858: /*
859: ===============
1.1.1.2 root 860: PM_FlyMove
1.1 root 861: ===============
862: */
1.1.1.2 root 863: void PM_FlyMove (qboolean doclip)
1.1 root 864: {
865: float speed, drop, friction, control, newspeed;
866: float currentspeed, addspeed, accelspeed;
867: int i;
868: vec3_t wishvel;
869: float fmove, smove;
870: vec3_t wishdir;
871: float wishspeed;
1.1.1.2 root 872: vec3_t end;
873: trace_t trace;
1.1 root 874:
875: pm->viewheight = 22;
1.1.1.2 root 876:
1.1 root 877: // friction
1.1.1.2 root 878:
1.1 root 879: speed = VectorLength (pml.velocity);
880: if (speed < 1)
881: {
882: VectorCopy (vec3_origin, pml.velocity);
883: }
884: else
885: {
886: drop = 0;
1.1.1.2 root 887:
1.1 root 888: friction = pm_friction*1.5; // extra friction
889: control = speed < pm_stopspeed ? pm_stopspeed : speed;
890: drop += control*friction*pml.frametime;
1.1.1.2 root 891:
1.1 root 892: // scale the velocity
893: newspeed = speed - drop;
894: if (newspeed < 0)
895: newspeed = 0;
896: newspeed /= speed;
1.1.1.2 root 897:
1.1 root 898: VectorScale (pml.velocity, newspeed, pml.velocity);
899: }
1.1.1.2 root 900:
1.1 root 901: // accelerate
902: fmove = pm->cmd.forwardmove;
903: smove = pm->cmd.sidemove;
904:
905: VectorNormalize (pml.forward);
906: VectorNormalize (pml.right);
1.1.1.2 root 907:
1.1 root 908: for (i=0 ; i<3 ; i++)
909: wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
910: wishvel[2] += pm->cmd.upmove;
1.1.1.2 root 911:
1.1 root 912: VectorCopy (wishvel, wishdir);
913: wishspeed = VectorNormalize(wishdir);
1.1.1.2 root 914:
1.1 root 915: //
916: // clamp to server defined max speed
917: //
918: if (wishspeed > pm_maxspeed)
919: {
920: VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
921: wishspeed = pm_maxspeed;
922: }
1.1.1.2 root 923:
924:
1.1 root 925: currentspeed = DotProduct(pml.velocity, wishdir);
926: addspeed = wishspeed - currentspeed;
927: if (addspeed <= 0)
928: return;
929: accelspeed = pm_accelerate*pml.frametime*wishspeed;
930: if (accelspeed > addspeed)
931: accelspeed = addspeed;
932:
933: for (i=0 ; i<3 ; i++)
934: pml.velocity[i] += accelspeed*wishdir[i];
1.1.1.2 root 935:
936: if (doclip) {
937: for (i=0 ; i<3 ; i++)
938: end[i] = pml.origin[i] + pml.frametime * pml.velocity[i];
939:
940: trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
941:
942: VectorCopy (trace.endpos, pml.origin);
943: } else {
944: // move
945: VectorMA (pml.origin, pml.frametime, pml.velocity, pml.origin);
946: }
1.1 root 947: }
1.1.1.2 root 948:
949:
1.1 root 950: /*
951: ==============
952: PM_CheckDuck
953:
954: Sets mins, maxs, and pm->viewheight
955: ==============
956: */
957: void PM_CheckDuck (void)
958: {
959: trace_t trace;
960:
961: pm->mins[0] = -16;
962: pm->mins[1] = -16;
963:
964: pm->maxs[0] = 16;
965: pm->maxs[1] = 16;
1.1.1.2 root 966:
1.1 root 967: if (pm->s.pm_type == PM_GIB)
968: {
969: pm->mins[2] = 0;
970: pm->maxs[2] = 16;
971: pm->viewheight = 8;
972: return;
973: }
974:
975: pm->mins[2] = -24;
976:
977: if (pm->s.pm_type == PM_DEAD)
978: {
979: pm->s.pm_flags |= PMF_DUCKED;
980: }
981: else if (pm->cmd.upmove < 0 && (pm->s.pm_flags & PMF_ON_GROUND) )
982: { // duck
983: pm->s.pm_flags |= PMF_DUCKED;
984: }
985: else
986: { // stand up if possible
987: if (pm->s.pm_flags & PMF_DUCKED)
988: {
989: // try to stand up
990: pm->maxs[2] = 32;
991: trace = pm->trace (pml.origin, pm->mins, pm->maxs, pml.origin);
992: if (!trace.allsolid)
993: pm->s.pm_flags &= ~PMF_DUCKED;
994: }
995: }
996:
997: if (pm->s.pm_flags & PMF_DUCKED)
998: {
999: pm->maxs[2] = 4;
1000: pm->viewheight = -2;
1001: }
1002: else
1003: {
1004: pm->maxs[2] = 32;
1005: pm->viewheight = 22;
1006: }
1007: }
1008:
1.1.1.2 root 1009:
1.1 root 1010: /*
1011: ==============
1012: PM_DeadMove
1013: ==============
1014: */
1015: void PM_DeadMove (void)
1016: {
1017: float forward;
1018:
1019: if (!pm->groundentity)
1020: return;
1021:
1022: // extra friction
1023:
1024: forward = VectorLength (pml.velocity);
1025: forward -= 20;
1026: if (forward <= 0)
1027: {
1028: VectorClear (pml.velocity);
1029: }
1030: else
1031: {
1032: VectorNormalize (pml.velocity);
1033: VectorScale (pml.velocity, forward, pml.velocity);
1034: }
1035: }
1036:
1037:
1038: qboolean PM_GoodPosition (void)
1039: {
1040: trace_t trace;
1041: vec3_t origin, end;
1042: int i;
1043:
1044: if (pm->s.pm_type == PM_SPECTATOR)
1045: return true;
1046:
1047: for (i=0 ; i<3 ; i++)
1048: origin[i] = end[i] = pm->s.origin[i]*0.125;
1049: trace = pm->trace (origin, pm->mins, pm->maxs, end);
1050:
1051: return !trace.allsolid;
1052: }
1053:
1054: /*
1055: ================
1056: PM_SnapPosition
1057:
1058: On exit, the origin will have a value that is pre-quantized to the 0.125
1059: precision of the network channel and in a valid position.
1060: ================
1061: */
1062: void PM_SnapPosition (void)
1063: {
1064: int sign[3];
1065: int i, j, bits;
1066: short base[3];
1067: // try all single bits first
1068: static int jitterbits[8] = {0,4,1,2,3,5,6,7};
1069:
1070: // snap velocity to eigths
1071: for (i=0 ; i<3 ; i++)
1072: pm->s.velocity[i] = (int)(pml.velocity[i]*8);
1073:
1074: for (i=0 ; i<3 ; i++)
1075: {
1076: if (pml.origin[i] >= 0)
1077: sign[i] = 1;
1078: else
1079: sign[i] = -1;
1080: pm->s.origin[i] = (int)(pml.origin[i]*8);
1081: if (pm->s.origin[i]*0.125 == pml.origin[i])
1082: sign[i] = 0;
1083: }
1084: VectorCopy (pm->s.origin, base);
1085:
1086: // try all combinations
1087: for (j=0 ; j<8 ; j++)
1088: {
1089: bits = jitterbits[j];
1090: VectorCopy (base, pm->s.origin);
1091: for (i=0 ; i<3 ; i++)
1092: if (bits & (1<<i) )
1093: pm->s.origin[i] += sign[i];
1094:
1095: if (PM_GoodPosition ())
1096: return;
1097: }
1098:
1099: // go back to the last position
1100: VectorCopy (pml.previous_origin, pm->s.origin);
1101: // Com_DPrintf ("using previous_origin\n");
1102: }
1103:
1.1.1.2 root 1104: #if 0
1105: //NO LONGER USED
1.1 root 1106: /*
1107: ================
1108: PM_InitialSnapPosition
1109:
1110: ================
1111: */
1112: void PM_InitialSnapPosition (void)
1113: {
1114: int x, y, z;
1115: short base[3];
1116:
1117: VectorCopy (pm->s.origin, base);
1118:
1119: for (z=1 ; z>=-1 ; z--)
1120: {
1121: pm->s.origin[2] = base[2] + z;
1122: for (y=1 ; y>=-1 ; y--)
1123: {
1124: pm->s.origin[1] = base[1] + y;
1125: for (x=1 ; x>=-1 ; x--)
1126: {
1127: pm->s.origin[0] = base[0] + x;
1128: if (PM_GoodPosition ())
1129: {
1130: pml.origin[0] = pm->s.origin[0]*0.125;
1131: pml.origin[1] = pm->s.origin[1]*0.125;
1132: pml.origin[2] = pm->s.origin[2]*0.125;
1133: VectorCopy (pm->s.origin, pml.previous_origin);
1134: return;
1135: }
1136: }
1137: }
1138: }
1139:
1140: Com_DPrintf ("Bad InitialSnapPosition\n");
1141: }
1.1.1.2 root 1142: #else
1143: /*
1144: ================
1145: PM_InitialSnapPosition
1146:
1147: ================
1148: */
1149: void PM_InitialSnapPosition(void)
1150: {
1151: int x, y, z;
1152: short base[3];
1153: static int offset[3] = { 0, -1, 1 };
1154:
1155: VectorCopy (pm->s.origin, base);
1156:
1157: for ( z = 0; z < 3; z++ ) {
1158: pm->s.origin[2] = base[2] + offset[ z ];
1159: for ( y = 0; y < 3; y++ ) {
1160: pm->s.origin[1] = base[1] + offset[ y ];
1161: for ( x = 0; x < 3; x++ ) {
1162: pm->s.origin[0] = base[0] + offset[ x ];
1163: if (PM_GoodPosition ()) {
1164: pml.origin[0] = pm->s.origin[0]*0.125;
1165: pml.origin[1] = pm->s.origin[1]*0.125;
1166: pml.origin[2] = pm->s.origin[2]*0.125;
1167: VectorCopy (pm->s.origin, pml.previous_origin);
1168: return;
1169: }
1170: }
1171: }
1172: }
1173:
1174: Com_DPrintf ("Bad InitialSnapPosition\n");
1175: }
1176:
1177: #endif
1.1 root 1178:
1179: /*
1180: ================
1181: PM_ClampAngles
1182:
1183: ================
1184: */
1185: void PM_ClampAngles (void)
1186: {
1187: short temp;
1188: int i;
1189:
1190: if (pm->s.pm_flags & PMF_TIME_TELEPORT)
1191: {
1192: pm->viewangles[YAW] = SHORT2ANGLE(pm->cmd.angles[YAW] + pm->s.delta_angles[YAW]);
1193: pm->viewangles[PITCH] = 0;
1194: pm->viewangles[ROLL] = 0;
1195: }
1196: else
1197: {
1198: // circularly clamp the angles with deltas
1199: for (i=0 ; i<3 ; i++)
1200: {
1201: temp = pm->cmd.angles[i] + pm->s.delta_angles[i];
1202: pm->viewangles[i] = SHORT2ANGLE(temp);
1203: }
1204:
1205: // don't let the player look up or down more than 90 degrees
1206: if (pm->viewangles[PITCH] > 89 && pm->viewangles[PITCH] < 180)
1207: pm->viewangles[PITCH] = 89;
1208: else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180)
1209: pm->viewangles[PITCH] = 271;
1210: }
1211: AngleVectors (pm->viewangles, pml.forward, pml.right, pml.up);
1212: }
1213:
1214: /*
1215: ================
1216: Pmove
1217:
1218: Can be called by either the server or the client
1219: ================
1220: */
1221: void Pmove (pmove_t *pmove)
1222: {
1223: pm = pmove;
1224:
1225: // clear results
1226: pm->numtouch = 0;
1227: VectorClear (pm->viewangles);
1228: pm->viewheight = 0;
1229: pm->groundentity = 0;
1230: pm->watertype = 0;
1231: pm->waterlevel = 0;
1232:
1233: // clear all pmove local vars
1234: memset (&pml, 0, sizeof(pml));
1235:
1236: // convert origin and velocity to float values
1237: pml.origin[0] = pm->s.origin[0]*0.125;
1238: pml.origin[1] = pm->s.origin[1]*0.125;
1239: pml.origin[2] = pm->s.origin[2]*0.125;
1240:
1241: pml.velocity[0] = pm->s.velocity[0]*0.125;
1242: pml.velocity[1] = pm->s.velocity[1]*0.125;
1243: pml.velocity[2] = pm->s.velocity[2]*0.125;
1244:
1245: // save old org in case we get stuck
1246: VectorCopy (pm->s.origin, pml.previous_origin);
1247:
1248: pml.frametime = pm->cmd.msec * 0.001;
1249:
1250: PM_ClampAngles ();
1251:
1252: if (pm->s.pm_type == PM_SPECTATOR)
1253: {
1.1.1.2 root 1254: PM_FlyMove (false);
1.1 root 1255: PM_SnapPosition ();
1256: return;
1257: }
1258:
1259: if (pm->s.pm_type >= PM_DEAD)
1260: {
1261: pm->cmd.forwardmove = 0;
1262: pm->cmd.sidemove = 0;
1263: pm->cmd.upmove = 0;
1264: }
1265:
1266: if (pm->s.pm_type == PM_FREEZE)
1267: return; // no movement at all
1268:
1269: // set mins, maxs, and viewheight
1270: PM_CheckDuck ();
1271:
1272: if (pm->snapinitial)
1273: PM_InitialSnapPosition ();
1274:
1275: // set groundentity, watertype, and waterlevel
1276: PM_CatagorizePosition ();
1277:
1278: if (pm->s.pm_type == PM_DEAD)
1279: PM_DeadMove ();
1280:
1281: PM_CheckSpecialMovement ();
1282:
1283: // drop timing counter
1284: if (pm->s.pm_time)
1285: {
1286: int msec;
1287:
1288: msec = pm->cmd.msec >> 3;
1289: if (!msec)
1290: msec = 1;
1291: if ( msec >= pm->s.pm_time)
1292: {
1293: pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
1294: pm->s.pm_time = 0;
1295: }
1296: else
1297: pm->s.pm_time -= msec;
1298: }
1299:
1300: if (pm->s.pm_flags & PMF_TIME_TELEPORT)
1301: { // teleport pause stays exactly in place
1302: }
1303: else if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
1304: { // waterjump has no control, but falls
1305: pml.velocity[2] -= pm->s.gravity * pml.frametime;
1306: if (pml.velocity[2] < 0)
1307: { // cancel as soon as we are falling down again
1308: pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
1309: pm->s.pm_time = 0;
1310: }
1311:
1312: PM_StepSlideMove ();
1313: }
1314: else
1315: {
1316: PM_CheckJump ();
1317:
1318: PM_Friction ();
1319:
1320: if (pm->waterlevel >= 2)
1321: PM_WaterMove ();
1.1.1.2 root 1322: else {
1323: vec3_t angles;
1324:
1325: VectorCopy(pm->viewangles, angles);
1326: if (angles[PITCH] > 180)
1327: angles[PITCH] = angles[PITCH] - 360;
1328: angles[PITCH] /= 3;
1329:
1330: AngleVectors (angles, pml.forward, pml.right, pml.up);
1331:
1.1 root 1332: PM_AirMove ();
1.1.1.2 root 1333: }
1.1 root 1334: }
1335:
1336: // set groundentity, watertype, and waterlevel for final spot
1337: PM_CatagorizePosition ();
1338:
1339: PM_SnapPosition ();
1340: }
1.1.1.2 root 1341:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.