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