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