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
36 vec3_t forward, right, up;
37 float frametime;
38
39
40 csurface_t *groundsurface;
41 cplane_t groundplane;
42 int groundcontents;
43
44 vec3_t previous_origin;
45 qboolean ladder;
46 } pml_t;
47
48 pmove_t *pm;
49 pml_t pml;
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
PM_ClipVelocity(vec3_t in,vec3_t normal,vec3_t out,float overbounce)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
PM_StepSlideMove_(void)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
167 VectorCopy (vec3_origin, pml.velocity);
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
206 VectorScale (pml.velocity, rub, pml.velocity);
207 }
208 else
209 {
210 // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
211 VectorCopy (vec3_origin, pml.velocity);
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);
240 VectorCopy (vec3_origin, pml.velocity);
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 {
254 VectorCopy (vec3_origin, pml.velocity);
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 */
PM_StepSlideMove(void)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
283 PM_StepSlideMove_ ();
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
299 PM_StepSlideMove_ ();
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
317 VectorCopy(pml.origin, up);
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 }
332 //!! Special case
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 */
PM_Friction(void)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
365 if ((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK) ) || (pml.ladder) )
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 */
PM_Accelerate(vec3_t wishdir,float wishspeed,float accel)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
PM_AirAccelerate(vec3_t wishdir,float wishspeed,float accel)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 */
PM_AddCurrents(vec3_t wishvel)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
481 if (pm->watertype & CONTENTS_CURRENT_0)
482 v[0] += 1;
483 if (pm->watertype & CONTENTS_CURRENT_90)
484 v[1] += 1;
485 if (pm->watertype & CONTENTS_CURRENT_180)
486 v[0] -= 1;
487 if (pm->watertype & CONTENTS_CURRENT_270)
488 v[1] -= 1;
489 if (pm->watertype & CONTENTS_CURRENT_UP)
490 v[2] += 1;
491 if (pm->watertype & CONTENTS_CURRENT_DOWN)
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
509 if (pml.groundcontents & CONTENTS_CURRENT_0)
510 v[0] += 1;
511 if (pml.groundcontents & CONTENTS_CURRENT_90)
512 v[1] += 1;
513 if (pml.groundcontents & CONTENTS_CURRENT_180)
514 v[0] -= 1;
515 if (pml.groundcontents & CONTENTS_CURRENT_270)
516 v[1] -= 1;
517 if (pml.groundcontents & CONTENTS_CURRENT_UP)
518 v[2] += 1;
519 if (pml.groundcontents & CONTENTS_CURRENT_DOWN)
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 */
PM_WaterMove(void)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 */
PM_AirMove(void)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
587 //!!!!! pitch should be 1/3 so this isn't needed??!
588 #if 0
589 pml.forward[2] = 0;
590 pml.right[2] = 0;
591 VectorNormalize (pml.forward);
592 VectorNormalize (pml.right);
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; //!!! this is before the accel
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 */
PM_CatagorizePosition(void)671 void PM_CatagorizePosition (void)
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) //!!ZOID changed from 100 to 180 (ramp accel)
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
708 if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
709 {
710 pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
711 pm->s.pm_time = 0;
712 }
713
714 if (! (pm->s.pm_flags & PMF_ON_GROUND) )
715 { // just hit the ground
716 pm->s.pm_flags |= PMF_ON_GROUND;
717 // don't do landing time if we were just going down a slope
718 if (pml.velocity[2] < -200)
719 {
720 pm->s.pm_flags |= PMF_TIME_LAND;
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 */
PM_CheckJump(void)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
817 pm->s.pm_flags |= PMF_JUMP_HELD;
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 */
PM_CheckSpecialMovement(void)831 void PM_CheckSpecialMovement (void)
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
872 pm->s.pm_flags |= PMF_TIME_WATERJUMP;
873 pm->s.pm_time = 255;
874 }
875
876
877 /*
878 ===============
879 PM_FlyMove
880 ===============
881 */
PM_FlyMove(qboolean doclip)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 {
901 VectorCopy (vec3_origin, pml.velocity);
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
924 VectorNormalize (pml.forward);
925 VectorNormalize (pml.right);
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
964 VectorMA (pml.origin, pml.frametime, pml.velocity, pml.origin);
965 }
966 }
967
968
969 /*
970 ==============
971 PM_CheckDuck
972
973 Sets mins, maxs, and pm->viewheight
974 ==============
975 */
PM_CheckDuck(void)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 */
PM_DeadMove(void)1034 void PM_DeadMove (void)
1035 {
1036 float forward;
1037
1038 if (!pm->groundentity)
1039 return;
1040
1041 // extra friction
1042
1043 forward = VectorLength (pml.velocity);
1044 forward -= 20;
1045 if (forward <= 0)
1046 {
1047 VectorClear (pml.velocity);
1048 }
1049 else
1050 {
1051 VectorNormalize (pml.velocity);
1052 VectorScale (pml.velocity, forward, pml.velocity);
1053 }
1054 }
1055
1056
PM_GoodPosition(void)1057 qboolean PM_GoodPosition (void)
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 */
PM_SnapPosition(void)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
1119 VectorCopy (pml.previous_origin, pm->s.origin);
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;
1152 VectorCopy (pm->s.origin, pml.previous_origin);
1153 return;
1154 }
1155 }
1156 }
1157 }
1158
1159 Com_DPrintf ("Bad InitialSnapPosition\n");
1160 }
1161 #else
1162 /*
1163 ================
1164 PM_InitialSnapPosition
1165
1166 ================
1167 */
PM_InitialSnapPosition(void)1168 void PM_InitialSnapPosition(void)
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;
1186 VectorCopy (pm->s.origin, pml.previous_origin);
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 */
PM_ClampAngles(void)1204 void PM_ClampAngles (void)
1205 {
1206 short temp;
1207 int i;
1208
1209 if (pm->s.pm_flags & PMF_TIME_TELEPORT)
1210 {
1211 pm->viewangles[YAW] = SHORT2ANGLE(pm->cmd.angles[YAW] + pm->s.delta_angles[YAW]);
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 }
1230 AngleVectors (pm->viewangles, pml.forward, pml.right, pml.up);
1231 }
1232
1233 /*
1234 ================
1235 Pmove
1236
1237 Can be called by either the server or the client
1238 ================
1239 */
Pmove(pmove_t * pmove)1240 void Pmove (pmove_t *pmove)
1241 {
1242 pm = pmove;
1243
1244 // clear results
1245 pm->numtouch = 0;
1246 VectorClear (pm->viewangles);
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
1265 VectorCopy (pm->s.origin, pml.previous_origin);
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)
1292 PM_InitialSnapPosition ();
1293
1294 // set groundentity, watertype, and waterlevel
1295 PM_CatagorizePosition ();
1296
1297 if (pm->s.pm_type == PM_DEAD)
1298 PM_DeadMove ();
1299
1300 PM_CheckSpecialMovement ();
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 {
1312 pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
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
1327 pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
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
1356 PM_CatagorizePosition ();
1357
1358 PM_SnapPosition ();
1359 }
1360
1361