|
|
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;
38: float pm_airaccelerate = 1;
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.2 ! root 354: if (pm->waterlevel >= 2 && !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.2 ! root 620: pml.velocity[2] -= pm->s.gravity * pml.frametime;
1.1 root 621: if (!pml.velocity[0] && !pml.velocity[1])
622: return;
623: PM_StepSlideMove ();
624: }
625: else
626: { // not on ground, so little effect on velocity
1.1.1.2 ! root 627: #if 0 // ZOID: Air control removed
! 628: PM_AirAccelerate (wishdir, wishspeed, pm_accelerate);
! 629: #else
1.1 root 630: PM_Accelerate (wishdir, wishspeed, pm_airaccelerate);
1.1.1.2 ! root 631: #endif
1.1 root 632: // add gravity
633: pml.velocity[2] -= pm->s.gravity * pml.frametime;
634: PM_StepSlideMove ();
635: }
636: }
1.1.1.2 ! root 637:
! 638:
! 639:
1.1 root 640: /*
641: =============
642: PM_CatagorizePosition
643: =============
644: */
645: void PM_CatagorizePosition (void)
646: {
647: vec3_t point;
648: int cont;
649: trace_t trace;
650: int sample1;
651: int sample2;
1.1.1.2 ! root 652:
1.1 root 653: // if the player hull point one unit down is solid, the player
654: // is on ground
1.1.1.2 ! root 655:
1.1 root 656: // see if standing on something solid
657: point[0] = pml.origin[0];
658: point[1] = pml.origin[1];
659: point[2] = pml.origin[2] - 0.25;
1.1.1.2 ! root 660: if (pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp accel)
1.1 root 661: {
662: pm->s.pm_flags &= ~PMF_ON_GROUND;
663: pm->groundentity = NULL;
664: }
665: else
666: {
667: trace = pm->trace (pml.origin, pm->mins, pm->maxs, point);
668: pml.groundplane = trace.plane;
669: pml.groundsurface = trace.surface;
670: pml.groundcontents = trace.contents;
671:
672: if (!trace.ent || (trace.plane.normal[2] < 0.7 && !trace.startsolid) )
673: {
674: pm->groundentity = NULL;
675: pm->s.pm_flags &= ~PMF_ON_GROUND;
676: }
677: else
678: {
679: pm->groundentity = trace.ent;
680:
681: // hitting solid ground will end a waterjump
682: if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
683: {
684: pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
685: pm->s.pm_time = 0;
686: }
687:
688: if (! (pm->s.pm_flags & PMF_ON_GROUND) )
689: { // just hit the ground
690: pm->s.pm_flags |= PMF_ON_GROUND;
691: // don't do landing time if we were just going down a slope
692: if (pml.velocity[2] < -200)
693: {
694: pm->s.pm_flags |= PMF_TIME_LAND;
695: // don't allow another jump for a little while
696: if (pml.velocity[2] < -400)
697: pm->s.pm_time = 25;
698: else
699: pm->s.pm_time = 18;
700: }
701: }
702: }
1.1.1.2 ! root 703:
! 704: #if 0
1.1 root 705: if (trace.fraction < 1.0 && trace.ent && pml.velocity[2] < 0)
706: pml.velocity[2] = 0;
1.1.1.2 ! root 707: #endif
1.1 root 708:
709: if (pm->numtouch < MAXTOUCH && trace.ent)
710: {
711: pm->touchents[pm->numtouch] = trace.ent;
712: pm->numtouch++;
713: }
714: }
1.1.1.2 ! root 715:
1.1 root 716: //
717: // get waterlevel, accounting for ducking
718: //
719: pm->waterlevel = 0;
720: pm->watertype = 0;
1.1.1.2 ! root 721:
1.1 root 722: sample2 = pm->viewheight - pm->mins[2];
723: sample1 = sample2 / 2;
1.1.1.2 ! root 724:
1.1 root 725: point[2] = pml.origin[2] + pm->mins[2] + 1;
726: cont = pm->pointcontents (point);
1.1.1.2 ! root 727:
1.1 root 728: if (cont & MASK_WATER)
729: {
730: pm->watertype = cont;
731: pm->waterlevel = 1;
732: point[2] = pml.origin[2] + pm->mins[2] + sample1;
733: cont = pm->pointcontents (point);
734: if (cont & MASK_WATER)
735: {
736: pm->waterlevel = 2;
737: point[2] = pml.origin[2] + pm->mins[2] + sample2;
738: cont = pm->pointcontents (point);
739: if (cont & MASK_WATER)
740: pm->waterlevel = 3;
741: }
742: }
1.1.1.2 ! root 743:
1.1 root 744: }
1.1.1.2 ! root 745:
! 746:
1.1 root 747: /*
748: =============
749: PM_CheckJump
750: =============
751: */
752: void PM_CheckJump (void)
753: {
754: if (pm->s.pm_flags & PMF_TIME_LAND)
755: { // hasn't been long enough since landing to jump again
756: return;
757: }
1.1.1.2 ! root 758:
1.1 root 759: if (pm->cmd.upmove < 10)
760: { // not holding jump
761: pm->s.pm_flags &= ~PMF_JUMP_HELD;
762: return;
763: }
764:
765: // must wait for jump to be released
766: if (pm->s.pm_flags & PMF_JUMP_HELD)
767: return;
768:
769: if (pm->s.pm_type == PM_DEAD)
770: return;
1.1.1.2 ! root 771:
1.1 root 772: if (pm->waterlevel >= 2)
773: { // swimming, not jumping
774: pm->groundentity = NULL;
1.1.1.2 ! root 775:
1.1 root 776: if (pml.velocity[2] <= -300)
777: return;
778:
779: if (pm->watertype == CONTENTS_WATER)
780: pml.velocity[2] = 100;
781: else if (pm->watertype == CONTENTS_SLIME)
782: pml.velocity[2] = 80;
783: else
784: pml.velocity[2] = 50;
785: return;
786: }
1.1.1.2 ! root 787:
1.1 root 788: if (pm->groundentity == NULL)
789: return; // in air, so no effect
1.1.1.2 ! root 790:
1.1 root 791: pm->s.pm_flags |= PMF_JUMP_HELD;
792:
793: pm->groundentity = NULL;
1.1.1.2 ! root 794: pml.velocity[2] += 270;
! 795: if (pml.velocity[2] < 270)
! 796: pml.velocity[2] = 270;
1.1 root 797: }
1.1.1.2 ! root 798:
! 799:
1.1 root 800: /*
801: =============
802: PM_CheckSpecialMovement
803: =============
804: */
805: void PM_CheckSpecialMovement (void)
806: {
807: vec3_t spot;
808: int cont;
809: vec3_t flatforward;
810: trace_t trace;
811:
812: if (pm->s.pm_time)
813: return;
814:
815: pml.ladder = false;
1.1.1.2 ! root 816:
1.1 root 817: // check for ladder
818: flatforward[0] = pml.forward[0];
819: flatforward[1] = pml.forward[1];
820: flatforward[2] = 0;
821: VectorNormalize (flatforward);
1.1.1.2 ! root 822:
1.1 root 823: VectorMA (pml.origin, 1, flatforward, spot);
824: trace = pm->trace (pml.origin, pm->mins, pm->maxs, spot);
825: if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER))
826: pml.ladder = true;
1.1.1.2 ! root 827:
1.1 root 828: // check for water jump
829: if (pm->waterlevel != 2)
830: return;
1.1.1.2 ! root 831:
1.1 root 832: VectorMA (pml.origin, 30, flatforward, spot);
833: spot[2] += 4;
834: cont = pm->pointcontents (spot);
835: if (!(cont & CONTENTS_SOLID))
836: return;
1.1.1.2 ! root 837:
1.1 root 838: spot[2] += 16;
839: cont = pm->pointcontents (spot);
840: if (cont)
841: return;
842: // jump out of water
1.1.1.2 ! root 843: VectorScale (flatforward, 50, pml.velocity);
1.1 root 844: pml.velocity[2] = 350;
845:
846: pm->s.pm_flags |= PMF_TIME_WATERJUMP;
847: pm->s.pm_time = 255;
848: }
1.1.1.2 ! root 849:
! 850:
1.1 root 851: /*
852: ===============
1.1.1.2 ! root 853: PM_FlyMove
1.1 root 854: ===============
855: */
1.1.1.2 ! root 856: void PM_FlyMove (qboolean doclip)
1.1 root 857: {
858: float speed, drop, friction, control, newspeed;
859: float currentspeed, addspeed, accelspeed;
860: int i;
861: vec3_t wishvel;
862: float fmove, smove;
863: vec3_t wishdir;
864: float wishspeed;
1.1.1.2 ! root 865: vec3_t end;
! 866: trace_t trace;
1.1 root 867:
868: pm->viewheight = 22;
1.1.1.2 ! root 869:
1.1 root 870: // friction
1.1.1.2 ! root 871:
1.1 root 872: speed = VectorLength (pml.velocity);
873: if (speed < 1)
874: {
875: VectorCopy (vec3_origin, pml.velocity);
876: }
877: else
878: {
879: drop = 0;
1.1.1.2 ! root 880:
1.1 root 881: friction = pm_friction*1.5; // extra friction
882: control = speed < pm_stopspeed ? pm_stopspeed : speed;
883: drop += control*friction*pml.frametime;
1.1.1.2 ! root 884:
1.1 root 885: // scale the velocity
886: newspeed = speed - drop;
887: if (newspeed < 0)
888: newspeed = 0;
889: newspeed /= speed;
1.1.1.2 ! root 890:
1.1 root 891: VectorScale (pml.velocity, newspeed, pml.velocity);
892: }
1.1.1.2 ! root 893:
1.1 root 894: // accelerate
895: fmove = pm->cmd.forwardmove;
896: smove = pm->cmd.sidemove;
897:
898: VectorNormalize (pml.forward);
899: VectorNormalize (pml.right);
1.1.1.2 ! root 900:
1.1 root 901: for (i=0 ; i<3 ; i++)
902: wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
903: wishvel[2] += pm->cmd.upmove;
1.1.1.2 ! root 904:
1.1 root 905: VectorCopy (wishvel, wishdir);
906: wishspeed = VectorNormalize(wishdir);
1.1.1.2 ! root 907:
1.1 root 908: //
909: // clamp to server defined max speed
910: //
911: if (wishspeed > pm_maxspeed)
912: {
913: VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
914: wishspeed = pm_maxspeed;
915: }
1.1.1.2 ! root 916:
! 917:
1.1 root 918: currentspeed = DotProduct(pml.velocity, wishdir);
919: addspeed = wishspeed - currentspeed;
920: if (addspeed <= 0)
921: return;
922: accelspeed = pm_accelerate*pml.frametime*wishspeed;
923: if (accelspeed > addspeed)
924: accelspeed = addspeed;
925:
926: for (i=0 ; i<3 ; i++)
927: pml.velocity[i] += accelspeed*wishdir[i];
1.1.1.2 ! root 928:
! 929: if (doclip) {
! 930: for (i=0 ; i<3 ; i++)
! 931: end[i] = pml.origin[i] + pml.frametime * pml.velocity[i];
! 932:
! 933: trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
! 934:
! 935: VectorCopy (trace.endpos, pml.origin);
! 936: } else {
! 937: // move
! 938: VectorMA (pml.origin, pml.frametime, pml.velocity, pml.origin);
! 939: }
1.1 root 940: }
1.1.1.2 ! root 941:
! 942:
1.1 root 943: /*
944: ==============
945: PM_CheckDuck
946:
947: Sets mins, maxs, and pm->viewheight
948: ==============
949: */
950: void PM_CheckDuck (void)
951: {
952: trace_t trace;
953:
954: pm->mins[0] = -16;
955: pm->mins[1] = -16;
956:
957: pm->maxs[0] = 16;
958: pm->maxs[1] = 16;
1.1.1.2 ! root 959:
1.1 root 960: if (pm->s.pm_type == PM_GIB)
961: {
962: pm->mins[2] = 0;
963: pm->maxs[2] = 16;
964: pm->viewheight = 8;
965: return;
966: }
967:
968: pm->mins[2] = -24;
969:
970: if (pm->s.pm_type == PM_DEAD)
971: {
972: pm->s.pm_flags |= PMF_DUCKED;
973: }
974: else if (pm->cmd.upmove < 0 && (pm->s.pm_flags & PMF_ON_GROUND) )
975: { // duck
976: pm->s.pm_flags |= PMF_DUCKED;
977: }
978: else
979: { // stand up if possible
980: if (pm->s.pm_flags & PMF_DUCKED)
981: {
982: // try to stand up
983: pm->maxs[2] = 32;
984: trace = pm->trace (pml.origin, pm->mins, pm->maxs, pml.origin);
985: if (!trace.allsolid)
986: pm->s.pm_flags &= ~PMF_DUCKED;
987: }
988: }
989:
990: if (pm->s.pm_flags & PMF_DUCKED)
991: {
992: pm->maxs[2] = 4;
993: pm->viewheight = -2;
994: }
995: else
996: {
997: pm->maxs[2] = 32;
998: pm->viewheight = 22;
999: }
1000: }
1001:
1.1.1.2 ! root 1002:
1.1 root 1003: /*
1004: ==============
1005: PM_DeadMove
1006: ==============
1007: */
1008: void PM_DeadMove (void)
1009: {
1010: float forward;
1011:
1012: if (!pm->groundentity)
1013: return;
1014:
1015: // extra friction
1016:
1017: forward = VectorLength (pml.velocity);
1018: forward -= 20;
1019: if (forward <= 0)
1020: {
1021: VectorClear (pml.velocity);
1022: }
1023: else
1024: {
1025: VectorNormalize (pml.velocity);
1026: VectorScale (pml.velocity, forward, pml.velocity);
1027: }
1028: }
1029:
1030:
1031: qboolean PM_GoodPosition (void)
1032: {
1033: trace_t trace;
1034: vec3_t origin, end;
1035: int i;
1036:
1037: if (pm->s.pm_type == PM_SPECTATOR)
1038: return true;
1039:
1040: for (i=0 ; i<3 ; i++)
1041: origin[i] = end[i] = pm->s.origin[i]*0.125;
1042: trace = pm->trace (origin, pm->mins, pm->maxs, end);
1043:
1044: return !trace.allsolid;
1045: }
1046:
1047: /*
1048: ================
1049: PM_SnapPosition
1050:
1051: On exit, the origin will have a value that is pre-quantized to the 0.125
1052: precision of the network channel and in a valid position.
1053: ================
1054: */
1055: void PM_SnapPosition (void)
1056: {
1057: int sign[3];
1058: int i, j, bits;
1059: short base[3];
1060: // try all single bits first
1061: static int jitterbits[8] = {0,4,1,2,3,5,6,7};
1062:
1063: // snap velocity to eigths
1064: for (i=0 ; i<3 ; i++)
1065: pm->s.velocity[i] = (int)(pml.velocity[i]*8);
1066:
1067: for (i=0 ; i<3 ; i++)
1068: {
1069: if (pml.origin[i] >= 0)
1070: sign[i] = 1;
1071: else
1072: sign[i] = -1;
1073: pm->s.origin[i] = (int)(pml.origin[i]*8);
1074: if (pm->s.origin[i]*0.125 == pml.origin[i])
1075: sign[i] = 0;
1076: }
1077: VectorCopy (pm->s.origin, base);
1078:
1079: // try all combinations
1080: for (j=0 ; j<8 ; j++)
1081: {
1082: bits = jitterbits[j];
1083: VectorCopy (base, pm->s.origin);
1084: for (i=0 ; i<3 ; i++)
1085: if (bits & (1<<i) )
1086: pm->s.origin[i] += sign[i];
1087:
1088: if (PM_GoodPosition ())
1089: return;
1090: }
1091:
1092: // go back to the last position
1093: VectorCopy (pml.previous_origin, pm->s.origin);
1094: // Com_DPrintf ("using previous_origin\n");
1095: }
1096:
1.1.1.2 ! root 1097: #if 0
! 1098: //NO LONGER USED
1.1 root 1099: /*
1100: ================
1101: PM_InitialSnapPosition
1102:
1103: ================
1104: */
1105: void PM_InitialSnapPosition (void)
1106: {
1107: int x, y, z;
1108: short base[3];
1109:
1110: VectorCopy (pm->s.origin, base);
1111:
1112: for (z=1 ; z>=-1 ; z--)
1113: {
1114: pm->s.origin[2] = base[2] + z;
1115: for (y=1 ; y>=-1 ; y--)
1116: {
1117: pm->s.origin[1] = base[1] + y;
1118: for (x=1 ; x>=-1 ; x--)
1119: {
1120: pm->s.origin[0] = base[0] + x;
1121: if (PM_GoodPosition ())
1122: {
1123: pml.origin[0] = pm->s.origin[0]*0.125;
1124: pml.origin[1] = pm->s.origin[1]*0.125;
1125: pml.origin[2] = pm->s.origin[2]*0.125;
1126: VectorCopy (pm->s.origin, pml.previous_origin);
1127: return;
1128: }
1129: }
1130: }
1131: }
1132:
1133: Com_DPrintf ("Bad InitialSnapPosition\n");
1134: }
1.1.1.2 ! root 1135: #else
! 1136: /*
! 1137: ================
! 1138: PM_InitialSnapPosition
! 1139:
! 1140: ================
! 1141: */
! 1142: void PM_InitialSnapPosition(void)
! 1143: {
! 1144: int x, y, z;
! 1145: short base[3];
! 1146: static int offset[3] = { 0, -1, 1 };
! 1147:
! 1148: VectorCopy (pm->s.origin, base);
! 1149:
! 1150: for ( z = 0; z < 3; z++ ) {
! 1151: pm->s.origin[2] = base[2] + offset[ z ];
! 1152: for ( y = 0; y < 3; y++ ) {
! 1153: pm->s.origin[1] = base[1] + offset[ y ];
! 1154: for ( x = 0; x < 3; x++ ) {
! 1155: pm->s.origin[0] = base[0] + offset[ x ];
! 1156: if (PM_GoodPosition ()) {
! 1157: pml.origin[0] = pm->s.origin[0]*0.125;
! 1158: pml.origin[1] = pm->s.origin[1]*0.125;
! 1159: pml.origin[2] = pm->s.origin[2]*0.125;
! 1160: VectorCopy (pm->s.origin, pml.previous_origin);
! 1161: return;
! 1162: }
! 1163: }
! 1164: }
! 1165: }
! 1166:
! 1167: Com_DPrintf ("Bad InitialSnapPosition\n");
! 1168: }
! 1169:
! 1170: #endif
1.1 root 1171:
1172: /*
1173: ================
1174: PM_ClampAngles
1175:
1176: ================
1177: */
1178: void PM_ClampAngles (void)
1179: {
1180: short temp;
1181: int i;
1182:
1183: if (pm->s.pm_flags & PMF_TIME_TELEPORT)
1184: {
1185: pm->viewangles[YAW] = SHORT2ANGLE(pm->cmd.angles[YAW] + pm->s.delta_angles[YAW]);
1186: pm->viewangles[PITCH] = 0;
1187: pm->viewangles[ROLL] = 0;
1188: }
1189: else
1190: {
1191: // circularly clamp the angles with deltas
1192: for (i=0 ; i<3 ; i++)
1193: {
1194: temp = pm->cmd.angles[i] + pm->s.delta_angles[i];
1195: pm->viewangles[i] = SHORT2ANGLE(temp);
1196: }
1197:
1198: // don't let the player look up or down more than 90 degrees
1199: if (pm->viewangles[PITCH] > 89 && pm->viewangles[PITCH] < 180)
1200: pm->viewangles[PITCH] = 89;
1201: else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180)
1202: pm->viewangles[PITCH] = 271;
1203: }
1204: AngleVectors (pm->viewangles, pml.forward, pml.right, pml.up);
1205: }
1206:
1207: /*
1208: ================
1209: Pmove
1210:
1211: Can be called by either the server or the client
1212: ================
1213: */
1214: void Pmove (pmove_t *pmove)
1215: {
1216: pm = pmove;
1217:
1218: // clear results
1219: pm->numtouch = 0;
1220: VectorClear (pm->viewangles);
1221: pm->viewheight = 0;
1222: pm->groundentity = 0;
1223: pm->watertype = 0;
1224: pm->waterlevel = 0;
1225:
1226: // clear all pmove local vars
1227: memset (&pml, 0, sizeof(pml));
1228:
1229: // convert origin and velocity to float values
1230: pml.origin[0] = pm->s.origin[0]*0.125;
1231: pml.origin[1] = pm->s.origin[1]*0.125;
1232: pml.origin[2] = pm->s.origin[2]*0.125;
1233:
1234: pml.velocity[0] = pm->s.velocity[0]*0.125;
1235: pml.velocity[1] = pm->s.velocity[1]*0.125;
1236: pml.velocity[2] = pm->s.velocity[2]*0.125;
1237:
1238: // save old org in case we get stuck
1239: VectorCopy (pm->s.origin, pml.previous_origin);
1240:
1241: pml.frametime = pm->cmd.msec * 0.001;
1242:
1243: PM_ClampAngles ();
1244:
1245: if (pm->s.pm_type == PM_SPECTATOR)
1246: {
1.1.1.2 ! root 1247: PM_FlyMove (false);
1.1 root 1248: PM_SnapPosition ();
1249: return;
1250: }
1251:
1252: if (pm->s.pm_type >= PM_DEAD)
1253: {
1254: pm->cmd.forwardmove = 0;
1255: pm->cmd.sidemove = 0;
1256: pm->cmd.upmove = 0;
1257: }
1258:
1259: if (pm->s.pm_type == PM_FREEZE)
1260: return; // no movement at all
1261:
1262: // set mins, maxs, and viewheight
1263: PM_CheckDuck ();
1264:
1265: if (pm->snapinitial)
1266: PM_InitialSnapPosition ();
1267:
1268: // set groundentity, watertype, and waterlevel
1269: PM_CatagorizePosition ();
1270:
1271: if (pm->s.pm_type == PM_DEAD)
1272: PM_DeadMove ();
1273:
1274: PM_CheckSpecialMovement ();
1275:
1276: // drop timing counter
1277: if (pm->s.pm_time)
1278: {
1279: int msec;
1280:
1281: msec = pm->cmd.msec >> 3;
1282: if (!msec)
1283: msec = 1;
1284: if ( msec >= pm->s.pm_time)
1285: {
1286: pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
1287: pm->s.pm_time = 0;
1288: }
1289: else
1290: pm->s.pm_time -= msec;
1291: }
1292:
1293: if (pm->s.pm_flags & PMF_TIME_TELEPORT)
1294: { // teleport pause stays exactly in place
1295: }
1296: else if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
1297: { // waterjump has no control, but falls
1298: pml.velocity[2] -= pm->s.gravity * pml.frametime;
1299: if (pml.velocity[2] < 0)
1300: { // cancel as soon as we are falling down again
1301: pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
1302: pm->s.pm_time = 0;
1303: }
1304:
1305: PM_StepSlideMove ();
1306: }
1307: else
1308: {
1309: PM_CheckJump ();
1310:
1311: PM_Friction ();
1312:
1313: if (pm->waterlevel >= 2)
1314: PM_WaterMove ();
1.1.1.2 ! root 1315: else {
! 1316: vec3_t angles;
! 1317:
! 1318: VectorCopy(pm->viewangles, angles);
! 1319: if (angles[PITCH] > 180)
! 1320: angles[PITCH] = angles[PITCH] - 360;
! 1321: angles[PITCH] /= 3;
! 1322:
! 1323: AngleVectors (angles, pml.forward, pml.right, pml.up);
! 1324:
1.1 root 1325: PM_AirMove ();
1.1.1.2 ! root 1326: }
1.1 root 1327: }
1328:
1329: // set groundentity, watertype, and waterlevel for final spot
1330: PM_CatagorizePosition ();
1331:
1332: PM_SnapPosition ();
1333: }
1.1.1.2 ! root 1334:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.