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 // sv_pmove.c
22 // Necessary to keep 3.21 compatibility and allow cgame dlls
23 //
24
25 #include "sv_local.h"
26
27 // all of the locals will be zeroed before each pmove, just to make damn sure
28 // we don't have any differences when running on client or server
29
30 typedef struct pMoveLocal_s {
31 vec3_t origin; // full float precision
32 vec3_t velocity; // full float precision
33
34 vec3_t forward, right, up;
35 float frameTime;
36
37 cBspSurface_t *groundSurface;
38 int groundContents;
39
40 svec3_t previousOrigin;
41 qBool ladder;
42 } pMoveLocal_t;
43
44 static pMoveNew_t *pm;
45 static pMoveLocal_t pml;
46
47 static float pmAirAcceleration = 0;
48
49 #define STEPSIZE 18
50 #define MIN_STEP_NORMAL 0.7f // can't step up onto very steep slopes
51 #define MAX_CLIP_PLANES 5
52
53 // movement parameters
54 #define SV_PM_STOPSPEED 100.0f
55 #define SV_PM_MAXSPEED 300.0f
56 #define SV_PM_DUCKSPEED 100.0f
57 #define SV_PM_ACCELERATE 10.0f
58 #define SV_PM_WATERACCELERATE 10.0f
59 #define SV_PM_FRICTION 6.0f
60 #define SV_PM_WATERFRICTION 1.0f
61 #define SV_PM_WATERSPEED 400.0f
62
63 /*
64 ==================
65 SV_PM_ClipVelocity
66
67 Slide off of the impacting object
68 returns the blocked flags (1 = floor, 2 = step / wall)
69 ==================
70 */
SV_PM_ClipVelocity(vec3_t in,vec3_t normal,vec3_t out,float overbounce)71 static void SV_PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) {
72 float backoff;
73 float change;
74 int i;
75
76 backoff = DotProduct (in, normal) * overbounce;
77
78 for (i=0 ; i<3 ; i++) {
79 change = normal[i]*backoff;
80 out[i] = in[i] - change;
81 if ((out[i] > -LARGE_EPSILON) && (out[i] < LARGE_EPSILON))
82 out[i] = 0;
83 }
84 }
85
86
87 /*
88 ==================
89 SV_PM_StepSlideMove
90
91 Each intersection will try to step over the obstruction instead of
92 sliding along it.
93
94 Returns a new origin, velocity, and contact entity
95 Does not modify any world state?
96 ==================
97 */
SV_PM_StepSlideMove_(void)98 static void SV_PM_StepSlideMove_ (void) {
99 int bumpcount, numbumps;
100 vec3_t dir;
101 float d;
102 int numPlanes;
103 vec3_t planes[MAX_CLIP_PLANES];
104 vec3_t primal_velocity;
105 int i, j;
106 trace_t trace;
107 vec3_t end;
108 float time_left;
109
110 numbumps = 4;
111
112 Vec3Copy (pml.velocity, primal_velocity);
113 numPlanes = 0;
114
115 time_left = pml.frameTime;
116
117 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) {
118 end[0] = pml.origin[0] + time_left * pml.velocity[0];
119 end[1] = pml.origin[1] + time_left * pml.velocity[1];
120 end[2] = pml.origin[2] + time_left * pml.velocity[2];
121
122 trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
123
124 if (trace.allSolid) {
125 // entity is trapped in another solid
126 pml.velocity[2] = 0; // don't build up falling damage
127 return;
128 }
129
130 if (trace.fraction > 0) {
131 // actually covered some distance
132 Vec3Copy (trace.endPos, pml.origin);
133 numPlanes = 0;
134 }
135
136 if (trace.fraction == 1)
137 break; // moved the entire distance
138
139 // save entity for contact
140 if ((pm->numTouch < MAXTOUCH) && trace.ent) {
141 pm->touchEnts[pm->numTouch] = trace.ent;
142 pm->numTouch++;
143 }
144
145 time_left -= time_left * trace.fraction;
146
147 // slide along this plane
148 if (numPlanes >= MAX_CLIP_PLANES) {
149 // this shouldn't really happen
150 Vec3Clear (pml.velocity);
151 break;
152 }
153
154 Vec3Copy (trace.plane.normal, planes[numPlanes]);
155 numPlanes++;
156
157 // modify original_velocity so it parallels all of the clip planes
158 for (i=0 ; i<numPlanes ; i++) {
159 SV_PM_ClipVelocity (pml.velocity, planes[i], pml.velocity, 1.01f);
160 for (j=0 ; j<numPlanes ; j++) {
161 if (j != i) {
162 if (DotProduct (pml.velocity, planes[j]) < 0)
163 break; // not ok
164 }
165 }
166 if (j == numPlanes)
167 break;
168 }
169
170 if (i != numPlanes) {
171 // go along this plane
172 }
173 else {
174 // go along the crease
175 if (numPlanes != 2) {
176 Vec3Clear (pml.velocity);
177 break;
178 }
179 CrossProduct (planes[0], planes[1], dir);
180 d = DotProduct (dir, pml.velocity);
181 Vec3Scale (dir, d, pml.velocity);
182 }
183
184 /*
185 ** if velocity is against the original velocity, stop dead
186 ** to avoid tiny occilations in sloping corners
187 */
188 if (DotProduct (pml.velocity, primal_velocity) <= 0) {
189 Vec3Clear (pml.velocity);
190 break;
191 }
192 }
193
194 if (pm->state.pmTime)
195 Vec3Copy (primal_velocity, pml.velocity);
196 }
197
SV_PM_StepSlideMove(void)198 static void SV_PM_StepSlideMove (void) {
199 vec3_t start_o, start_v;
200 vec3_t down_o, down_v;
201 trace_t trace;
202 float down_dist, up_dist;
203 vec3_t up, down;
204
205 Vec3Copy (pml.origin, start_o);
206 Vec3Copy (pml.velocity, start_v);
207
208 SV_PM_StepSlideMove_ ();
209
210 Vec3Copy (pml.origin, down_o);
211 Vec3Copy (pml.velocity, down_v);
212
213 Vec3Copy (start_o, up);
214 up[2] += STEPSIZE;
215
216 trace = pm->trace (up, pm->mins, pm->maxs, up);
217 if (trace.allSolid)
218 return; // can't step up
219
220 // try sliding above
221 Vec3Copy (up, pml.origin);
222 Vec3Copy (start_v, pml.velocity);
223
224 SV_PM_StepSlideMove_ ();
225
226 // push down the final amount
227 Vec3Copy (pml.origin, down);
228 down[2] -= STEPSIZE;
229 trace = pm->trace (pml.origin, pm->mins, pm->maxs, down);
230 if (!trace.allSolid)
231 Vec3Copy (trace.endPos, pml.origin);
232
233 Vec3Copy (pml.origin, up);
234
235 // decide which one went farther
236 down_dist = (down_o[0] - start_o[0])*(down_o[0] - start_o[0])
237 + (down_o[1] - start_o[1])*(down_o[1] - start_o[1]);
238 up_dist = (up[0] - start_o[0])*(up[0] - start_o[0])
239 + (up[1] - start_o[1])*(up[1] - start_o[1]);
240
241 if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL) {
242 Vec3Copy (down_o, pml.origin);
243 Vec3Copy (down_v, pml.velocity);
244 return;
245 }
246 // !! Special case !!
247 // if we were walking along a plane, then we need to copy the Z over
248 pml.velocity[2] = down_v[2];
249 }
250
251
252 /*
253 ==================
254 SV_PM_Friction
255
256 Handles both ground friction and water friction
257 ==================
258 */
SV_PM_Friction(void)259 static void SV_PM_Friction (void) {
260 float *vel;
261 float speed, newspeed, control;
262 float friction;
263 float drop;
264
265 vel = pml.velocity;
266
267 speed = Vec3Length (vel);
268 if (speed < 1) {
269 vel[0] = 0;
270 vel[1] = 0;
271 return;
272 }
273
274 drop = 0;
275
276 // apply ground friction
277 if ((pm->groundEntity && pml.groundSurface && !(pml.groundSurface->flags & SURF_TEXINFO_SLICK)) || pml.ladder) {
278 friction = SV_PM_FRICTION;
279 control = (speed < SV_PM_STOPSPEED) ? SV_PM_STOPSPEED : speed;
280 drop += control*friction*pml.frameTime;
281 }
282
283 // apply water friction
284 if (pm->waterLevel && !pml.ladder)
285 drop += speed*SV_PM_WATERFRICTION*pm->waterLevel*pml.frameTime;
286
287 // scale the velocity
288 newspeed = speed - drop;
289 if (newspeed < 0)
290 newspeed = 0;
291
292 newspeed /= speed;
293
294 vel[0] = vel[0] * newspeed;
295 vel[1] = vel[1] * newspeed;
296 vel[2] = vel[2] * newspeed;
297 }
298
299
300 /*
301 ==============
302 SV_PM_Accelerate
303
304 Handles user intended acceleration
305 ==============
306 */
SV_PM_Accelerate(vec3_t wishdir,float wishspeed,float accel)307 static void SV_PM_Accelerate (vec3_t wishdir, float wishspeed, float accel) {
308 float addspeed, accelspeed, currentspeed;
309
310 currentspeed = DotProduct (pml.velocity, wishdir);
311 addspeed = wishspeed - currentspeed;
312 if (addspeed <= 0)
313 return;
314
315 accelspeed = accel*pml.frameTime*wishspeed;
316 if (accelspeed > addspeed)
317 accelspeed = addspeed;
318
319 pml.velocity[0] += accelspeed*wishdir[0];
320 pml.velocity[1] += accelspeed*wishdir[1];
321 pml.velocity[2] += accelspeed*wishdir[2];
322 }
323
324
325 /*
326 ==============
327 SV_PM_AirAccelerate
328
329 Handles user intended air acceleration
330 ==============
331 */
SV_PM_AirAccelerate(vec3_t wishdir,float wishspeed,float accel)332 static void SV_PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel) {
333 float addspeed, accelspeed;
334 float currentspeed, wishspd = wishspeed;
335
336 if (wishspd > 30)
337 wishspd = 30;
338 currentspeed = DotProduct (pml.velocity, wishdir);
339 addspeed = wishspd - currentspeed;
340 if (addspeed <= 0)
341 return;
342
343 accelspeed = accel * wishspeed * pml.frameTime;
344 if (accelspeed > addspeed)
345 accelspeed = addspeed;
346
347 pml.velocity[0] += accelspeed*wishdir[0];
348 pml.velocity[1] += accelspeed*wishdir[1];
349 pml.velocity[2] += accelspeed*wishdir[2];
350 }
351
352
353 /*
354 =============
355 SV_PM_AddCurrents
356 =============
357 */
SV_PM_AddCurrents(vec3_t wishvel)358 static void SV_PM_AddCurrents (vec3_t wishvel) {
359 vec3_t v;
360 float s;
361
362 // account for ladders
363 if (pml.ladder && fabs (pml.velocity[2]) <= 200) {
364 if ((pm->viewAngles[PITCH] <= -15) && (pm->cmd.forwardMove > 0))
365 wishvel[2] = 200;
366 else if ((pm->viewAngles[PITCH] >= 15) && (pm->cmd.forwardMove > 0))
367 wishvel[2] = -200;
368 else if (pm->cmd.upMove > 0)
369 wishvel[2] = 200;
370 else if (pm->cmd.upMove < 0)
371 wishvel[2] = -200;
372 else
373 wishvel[2] = 0;
374
375 // limit horizontal speed when on a ladder
376 if (wishvel[0] < -25) wishvel[0] = -25;
377 else if (wishvel[0] > 25) wishvel[0] = 25;
378
379 if (wishvel[1] < -25) wishvel[1] = -25;
380 else if (wishvel[1] > 25) wishvel[1] = 25;
381 }
382
383 // add water currents
384 if (pm->waterType & MASK_CURRENT) {
385 Vec3Clear (v);
386
387 if (pm->waterType & CONTENTS_CURRENT_0) v[0] += 1;
388 if (pm->waterType & CONTENTS_CURRENT_90) v[1] += 1;
389 if (pm->waterType & CONTENTS_CURRENT_180) v[0] -= 1;
390 if (pm->waterType & CONTENTS_CURRENT_270) v[1] -= 1;
391 if (pm->waterType & CONTENTS_CURRENT_UP) v[2] += 1;
392 if (pm->waterType & CONTENTS_CURRENT_DOWN) v[2] -= 1;
393
394 s = SV_PM_WATERSPEED;
395 if ((pm->waterLevel == 1) && (pm->groundEntity))
396 s /= 2;
397
398 Vec3MA (wishvel, s, v, wishvel);
399 }
400
401 // add conveyor belt velocities
402 if (pm->groundEntity) {
403 Vec3Clear (v);
404
405 if (pml.groundContents & CONTENTS_CURRENT_0) v[0] += 1;
406 if (pml.groundContents & CONTENTS_CURRENT_90) v[1] += 1;
407 if (pml.groundContents & CONTENTS_CURRENT_180) v[0] -= 1;
408 if (pml.groundContents & CONTENTS_CURRENT_270) v[1] -= 1;
409 if (pml.groundContents & CONTENTS_CURRENT_UP) v[2] += 1;
410 if (pml.groundContents & CONTENTS_CURRENT_DOWN) v[2] -= 1;
411
412 Vec3MA (wishvel, 100 /* pm->groundEntity->speed */, v, wishvel);
413 }
414 }
415
416
417 /*
418 ===================
419 SV_PM_WaterMove
420 ===================
421 */
SV_PM_WaterMove(void)422 static void SV_PM_WaterMove (void) {
423 vec3_t wishvel, wishdir;
424 float wishspeed;
425
426 // user intentions
427 wishvel[0] = pml.forward[0]*pm->cmd.forwardMove + pml.right[0]*pm->cmd.sideMove;
428 wishvel[1] = pml.forward[1]*pm->cmd.forwardMove + pml.right[1]*pm->cmd.sideMove;
429 wishvel[2] = pml.forward[2]*pm->cmd.forwardMove + pml.right[2]*pm->cmd.sideMove;
430
431 if (!pm->cmd.forwardMove && !pm->cmd.sideMove && !pm->cmd.upMove)
432 wishvel[2] -= 60; // drift towards bottom
433 else
434 wishvel[2] += pm->cmd.upMove;
435
436 SV_PM_AddCurrents (wishvel);
437
438 Vec3Copy (wishvel, wishdir);
439 wishspeed = VectorNormalizef (wishdir, wishdir);
440
441 if (wishspeed > SV_PM_MAXSPEED) {
442 Vec3Scale (wishvel, SV_PM_MAXSPEED/wishspeed, wishvel);
443 wishspeed = SV_PM_MAXSPEED;
444 }
445 wishspeed *= 0.5;
446
447 SV_PM_Accelerate (wishdir, wishspeed, SV_PM_WATERACCELERATE);
448
449 SV_PM_StepSlideMove ();
450 }
451
452
453 /*
454 ===================
455 SV_PM_AirMove
456 ===================
457 */
SV_PM_AirMove(void)458 static void SV_PM_AirMove (void) {
459 vec3_t wishvel, wishdir;
460 float fmove, smove;
461 float wishspeed;
462 float maxspeed;
463
464 fmove = pm->cmd.forwardMove;
465 smove = pm->cmd.sideMove;
466
467 wishvel[0] = pml.forward[0]*fmove + pml.right[0]*smove;
468 wishvel[1] = pml.forward[1]*fmove + pml.right[1]*smove;
469 wishvel[2] = 0;
470
471 SV_PM_AddCurrents (wishvel);
472
473 Vec3Copy (wishvel, wishdir);
474 wishspeed = VectorNormalizef (wishdir, wishdir);
475
476 // clamp to server defined max speed
477 maxspeed = (pm->state.pmFlags & PMF_DUCKED) ? SV_PM_DUCKSPEED : SV_PM_MAXSPEED;
478
479 if (wishspeed > maxspeed) {
480 Vec3Scale (wishvel, maxspeed/wishspeed, wishvel);
481 wishspeed = maxspeed;
482 }
483
484 if (pml.ladder) {
485 SV_PM_Accelerate (wishdir, wishspeed, SV_PM_ACCELERATE);
486 if (!wishvel[2]) {
487 if (pml.velocity[2] > 0) {
488 pml.velocity[2] -= pm->state.gravity * pml.frameTime;
489 if (pml.velocity[2] < 0)
490 pml.velocity[2] = 0;
491 }
492 else {
493 pml.velocity[2] += pm->state.gravity * pml.frameTime;
494 if (pml.velocity[2] > 0)
495 pml.velocity[2] = 0;
496 }
497 }
498
499 SV_PM_StepSlideMove ();
500 }
501 else if (pm->groundEntity) {
502 // walking on ground
503 pml.velocity[2] = 0; //!!! this is before the accel
504 SV_PM_Accelerate (wishdir, wishspeed, SV_PM_ACCELERATE);
505
506 // PGM -- fix for negative trigger_gravity fields
507 // pml.velocity[2] = 0;
508 if (pm->state.gravity > 0)
509 pml.velocity[2] = 0;
510 else
511 pml.velocity[2] -= pm->state.gravity * pml.frameTime;
512 // PGM
513
514 if (!pml.velocity[0] && !pml.velocity[1])
515 return;
516 SV_PM_StepSlideMove ();
517 }
518 else {
519 // not on ground, so little effect on velocity
520 if (pmAirAcceleration)
521 SV_PM_AirAccelerate (wishdir, wishspeed, SV_PM_ACCELERATE);
522 else
523 SV_PM_Accelerate (wishdir, wishspeed, 1);
524
525 // add gravity
526 pml.velocity[2] -= pm->state.gravity * pml.frameTime;
527 SV_PM_StepSlideMove ();
528 }
529 }
530
531
532 /*
533 =============
534 SV_PM_CatagorizePosition
535 =============
536 */
SV_PM_CatagorizePosition(void)537 static void SV_PM_CatagorizePosition (void) {
538 vec3_t point;
539 int cont;
540 trace_t trace;
541 float sample1;
542 float sample2;
543
544 // if the player hull point one unit down is solid, the player is on ground
545 // see if standing on something solid
546 point[0] = pml.origin[0];
547 point[1] = pml.origin[1];
548 point[2] = pml.origin[2] - 0.25;
549
550 if (pml.velocity[2] > 180) {
551 pm->state.pmFlags &= ~PMF_ON_GROUND;
552 pm->groundEntity = NULL;
553 }
554 else {
555 trace = pm->trace (pml.origin, pm->mins, pm->maxs, point);
556 pml.groundSurface = trace.surface;
557 pml.groundContents = trace.contents;
558
559 if (!trace.ent || ((trace.plane.normal[2] < 0.7) && !trace.startSolid)) {
560 pm->groundEntity = NULL;
561 pm->state.pmFlags &= ~PMF_ON_GROUND;
562 }
563 else {
564 pm->groundEntity = trace.ent;
565
566 // hitting solid ground will end a waterjump
567 if (pm->state.pmFlags & PMF_TIME_WATERJUMP) {
568 pm->state.pmFlags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
569 pm->state.pmTime = 0;
570 }
571
572 if (!(pm->state.pmFlags & PMF_ON_GROUND)) {
573 // just hit the ground
574 pm->state.pmFlags |= PMF_ON_GROUND;
575 // don't do landing time if we were just going down a slope
576 if (pml.velocity[2] < -200) {
577 pm->state.pmFlags |= PMF_TIME_LAND;
578 // don't allow another jump for a little while
579 if (pml.velocity[2] < -400)
580 pm->state.pmTime = 25;
581 else
582 pm->state.pmTime = 18;
583 }
584 }
585 }
586
587 if ((pm->numTouch < MAXTOUCH) && trace.ent) {
588 pm->touchEnts[pm->numTouch] = trace.ent;
589 pm->numTouch++;
590 }
591 }
592
593 // get waterLevel, accounting for ducking
594 pm->waterLevel = 0;
595 pm->waterType = 0;
596
597 sample2 = pm->viewHeight - pm->mins[2];
598 sample1 = sample2 / 2;
599
600 point[2] = pml.origin[2] + pm->mins[2] + 1;
601 cont = pm->pointContents (point);
602
603 if (cont & MASK_WATER) {
604 pm->waterType = cont;
605 pm->waterLevel = 1;
606 point[2] = pml.origin[2] + pm->mins[2] + sample1;
607 cont = pm->pointContents (point);
608 if (cont & MASK_WATER) {
609 pm->waterLevel = 2;
610 point[2] = pml.origin[2] + pm->mins[2] + sample2;
611 cont = pm->pointContents (point);
612 if (cont & MASK_WATER)
613 pm->waterLevel = 3;
614 }
615 }
616 }
617
618
619 /*
620 =============
621 SV_PM_CheckJump
622 =============
623 */
SV_PM_CheckJump(void)624 static void SV_PM_CheckJump (void) {
625 if (pm->state.pmFlags & PMF_TIME_LAND) {
626 // hasn't been long enough since landing to jump again
627 return;
628 }
629
630 if (pm->cmd.upMove < 10) {
631 // not holding jump
632 pm->state.pmFlags &= ~PMF_JUMP_HELD;
633 return;
634 }
635
636 // must wait for jump to be released
637 if (pm->state.pmFlags & PMF_JUMP_HELD)
638 return;
639
640 if (pm->state.pmType == PMT_DEAD)
641 return;
642
643 if (pm->waterLevel >= 2) {
644 // swimming, not jumping
645 pm->groundEntity = NULL;
646
647 if (pml.velocity[2] <= -300)
648 return;
649
650 if (pm->waterType == CONTENTS_WATER)
651 pml.velocity[2] = 100;
652 else if (pm->waterType == CONTENTS_SLIME)
653 pml.velocity[2] = 80;
654 else
655 pml.velocity[2] = 50;
656 return;
657 }
658
659 if (pm->groundEntity == NULL)
660 return; // in air, so no effect
661
662 pm->state.pmFlags |= PMF_JUMP_HELD;
663
664 pm->groundEntity = NULL;
665 pml.velocity[2] += 270;
666 if (pml.velocity[2] < 270)
667 pml.velocity[2] = 270;
668 }
669
670
671 /*
672 =============
673 SV_PM_CheckSpecialMovement
674 =============
675 */
SV_PM_CheckSpecialMovement(void)676 static void SV_PM_CheckSpecialMovement (void) {
677 vec3_t spot;
678 int cont;
679 vec3_t flatforward;
680 trace_t trace;
681
682 if (pm->state.pmTime)
683 return;
684
685 pml.ladder = qFalse;
686
687 // check for ladder
688 flatforward[0] = pml.forward[0];
689 flatforward[1] = pml.forward[1];
690 flatforward[2] = 0;
691 VectorNormalizef (flatforward, flatforward);
692
693 Vec3MA (pml.origin, 1, flatforward, spot);
694 trace = pm->trace (pml.origin, pm->mins, pm->maxs, spot);
695 if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER))
696 pml.ladder = qTrue;
697
698 // check for water jump
699 if (pm->waterLevel != 2)
700 return;
701
702 Vec3MA (pml.origin, 30, flatforward, spot);
703 spot[2] += 4;
704 cont = pm->pointContents (spot);
705 if (!(cont & CONTENTS_SOLID))
706 return;
707
708 spot[2] += 16;
709 cont = pm->pointContents (spot);
710 if (cont)
711 return;
712
713 // jump out of water
714 Vec3Scale (flatforward, 50, pml.velocity);
715 pml.velocity[2] = 350;
716
717 pm->state.pmFlags |= PMF_TIME_WATERJUMP;
718 pm->state.pmTime = 255;
719 }
720
721
722 /*
723 ===============
724 SV_PM_FlyMove
725 ===============
726 */
SV_PM_FlyMove(qBool doClip)727 static void SV_PM_FlyMove (qBool doClip) {
728 float speed, drop, friction, control, newspeed;
729 float currentspeed, addspeed, accelspeed;
730 vec3_t wishvel, wishdir, end;
731 float fmove, smove, wishspeed;
732 trace_t trace;
733
734 pm->viewHeight = 22;
735
736 // friction
737 speed = Vec3Length (pml.velocity);
738 if (speed < 1)
739 Vec3Clear (pml.velocity);
740 else {
741 drop = 0;
742
743 friction = SV_PM_FRICTION*1.5; // extra friction
744 control = (speed < SV_PM_STOPSPEED) ? SV_PM_STOPSPEED : speed;
745 drop += control*friction*pml.frameTime;
746
747 // scale the velocity
748 newspeed = speed - drop;
749 if (newspeed < 0)
750 newspeed = 0;
751 newspeed /= speed;
752
753 Vec3Scale (pml.velocity, newspeed, pml.velocity);
754 }
755
756 // accelerate
757 fmove = pm->cmd.forwardMove;
758 smove = pm->cmd.sideMove;
759
760 VectorNormalizef (pml.forward, pml.forward);
761 VectorNormalizef (pml.right, pml.right);
762
763 wishvel[0] = pml.forward[0]*fmove + pml.right[0]*smove;
764 wishvel[1] = pml.forward[1]*fmove + pml.right[1]*smove;
765 wishvel[2] = pml.forward[2]*fmove + pml.right[2]*smove + pm->cmd.upMove;
766
767 Vec3Copy (wishvel, wishdir);
768 wishspeed = VectorNormalizef (wishdir, wishdir);
769
770 // clamp to server defined max speed
771 if (wishspeed > SV_PM_MAXSPEED) {
772 Vec3Scale (wishvel, SV_PM_MAXSPEED/wishspeed, wishvel);
773 wishspeed = SV_PM_MAXSPEED;
774 }
775
776 currentspeed = DotProduct (pml.velocity, wishdir);
777 addspeed = wishspeed - currentspeed;
778 if (addspeed <= 0)
779 return;
780
781 accelspeed = SV_PM_ACCELERATE*pml.frameTime*wishspeed;
782 if (accelspeed > addspeed)
783 accelspeed = addspeed;
784
785 pml.velocity[0] += accelspeed*wishdir[0];
786 pml.velocity[1] += accelspeed*wishdir[1];
787 pml.velocity[2] += accelspeed*wishdir[2];
788
789 if (doClip) {
790 end[0] = pml.origin[0] + pml.frameTime * pml.velocity[0];
791 end[1] = pml.origin[1] + pml.frameTime * pml.velocity[1];
792 end[2] = pml.origin[2] + pml.frameTime * pml.velocity[2];
793
794 trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
795
796 Vec3Copy (trace.endPos, pml.origin);
797 }
798 else {
799 // move
800 Vec3MA (pml.origin, pml.frameTime, pml.velocity, pml.origin);
801 }
802 }
803
804
805 /*
806 ==============
807 SV_PM_CheckDuck
808
809 Sets mins, maxs, and pm->viewHeight
810 ==============
811 */
SV_PM_CheckDuck(void)812 static void SV_PM_CheckDuck (void) {
813 trace_t trace;
814
815 pm->mins[0] = -16;
816 pm->mins[1] = -16;
817
818 pm->maxs[0] = 16;
819 pm->maxs[1] = 16;
820
821 if (pm->state.pmType == PMT_GIB) {
822 pm->mins[2] = 0;
823 pm->maxs[2] = 16;
824 pm->viewHeight = 8;
825 return;
826 }
827
828 pm->mins[2] = -24;
829
830 if (pm->state.pmType == PMT_DEAD) {
831 pm->state.pmFlags |= PMF_DUCKED;
832 }
833 else if (pm->cmd.upMove < 0 && (pm->state.pmFlags & PMF_ON_GROUND)) {
834 // duck
835 pm->state.pmFlags |= PMF_DUCKED;
836 }
837 else {
838 // stand up if possible
839 if (pm->state.pmFlags & PMF_DUCKED) {
840 // try to stand up
841 pm->maxs[2] = 32;
842 trace = pm->trace (pml.origin, pm->mins, pm->maxs, pml.origin);
843 if (!trace.allSolid)
844 pm->state.pmFlags &= ~PMF_DUCKED;
845 }
846 }
847
848 if (pm->state.pmFlags & PMF_DUCKED) {
849 pm->maxs[2] = 4;
850 pm->viewHeight = -2;
851 }
852 else {
853 pm->maxs[2] = 32;
854 pm->viewHeight = 22;
855 }
856 }
857
858
859 /*
860 ==============
861 SV_PM_DeadMove
862 ==============
863 */
SV_PM_DeadMove(void)864 static void SV_PM_DeadMove (void)
865 {
866 float forward;
867
868 if (!pm->groundEntity)
869 return;
870
871 // extra friction
872 forward = Vec3Length (pml.velocity);
873 forward -= 20;
874 if (forward <= 0)
875 Vec3Clear (pml.velocity);
876 else {
877 VectorNormalizef (pml.velocity, pml.velocity);
878 Vec3Scale (pml.velocity, forward, pml.velocity);
879 }
880 }
881
882
883 /*
884 ================
885 SV_PM_GoodPosition
886 ================
887 */
SV_PM_GoodPosition(void)888 static qBool SV_PM_GoodPosition (void)
889 {
890 trace_t trace;
891 vec3_t origin, end;
892
893 if (pm->state.pmType == PMT_SPECTATOR)
894 return qTrue;
895
896 origin[0] = end[0] = pm->state.origin[0]*(1.0f/8.0f);
897 origin[1] = end[1] = pm->state.origin[1]*(1.0f/8.0f);
898 origin[2] = end[2] = pm->state.origin[2]*(1.0f/8.0f);
899 trace = pm->trace (origin, pm->mins, pm->maxs, end);
900
901 return !trace.allSolid;
902 }
903
904
905 /*
906 ================
907 SV_PM_SnapPosition
908
909 On exit, the origin will have a value that is pre-quantized to the (1.0f/8.0f)
910 precision of the network channel and in a valid position.
911 ================
912 */
SV_PM_SnapPosition(void)913 static void SV_PM_SnapPosition (void)
914 {
915 int sign[3];
916 int i, bits;
917 int16 base[3];
918 // try all single bits first
919 static const int jitterBits[8] = {0,4,1,2,3,5,6,7};
920
921 // snap velocity to eigths
922 pm->state.velocity[0] = (int)(pml.velocity[0]*8);
923 pm->state.velocity[1] = (int)(pml.velocity[1]*8);
924 pm->state.velocity[2] = (int)(pml.velocity[2]*8);
925
926 for (i=0 ; i<3 ; i++) {
927 if (pml.origin[i] >= 0)
928 sign[i] = 1;
929 else
930 sign[i] = -1;
931 pm->state.origin[i] = (int)(pml.origin[i]*8);
932 if (pm->state.origin[i]*(1.0f/8.0f) == pml.origin[i])
933 sign[i] = 0;
934 }
935 Vec3Copy (pm->state.origin, base);
936
937 // try all combinations
938 for (i=0 ; i<8 ; i++) {
939 bits = jitterBits[i];
940 Vec3Copy (base, pm->state.origin);
941
942 if (bits & (1<<0))
943 pm->state.origin[0] += sign[0];
944 if (bits & (1<<1))
945 pm->state.origin[1] += sign[1];
946 if (bits & (1<<2))
947 pm->state.origin[2] += sign[2];
948
949 if (SV_PM_GoodPosition ())
950 return;
951 }
952
953 // go back to the last position
954 Vec3Copy (pml.previousOrigin, pm->state.origin);
955 }
956
957
958 /*
959 ================
960 SV_PM_InitialSnapPosition
961 ================
962 */
SV_PM_InitialSnapPosition(void)963 static void SV_PM_InitialSnapPosition (void) {
964 int x, y, z;
965 int16 base[3];
966 static int offset[3] = { 0, -1, 1 };
967
968 Vec3Copy (pm->state.origin, base);
969
970 for (z=0 ; z<3 ; z++) {
971 pm->state.origin[2] = base[2] + offset[z];
972 for (y=0 ; y<3 ; y++) {
973 pm->state.origin[1] = base[1] + offset[y];
974 for (x=0 ; x<3 ; x++) {
975 pm->state.origin[0] = base[0] + offset[x];
976 if (SV_PM_GoodPosition ()) {
977 pml.origin[0] = pm->state.origin[0]*(1.0f/8.0f);
978 pml.origin[1] = pm->state.origin[1]*(1.0f/8.0f);
979 pml.origin[2] = pm->state.origin[2]*(1.0f/8.0f);
980 Vec3Copy (pm->state.origin, pml.previousOrigin);
981 return;
982 }
983 }
984 }
985 }
986
987 Com_DevPrintf (PRNT_WARNING, "Bad InitialSnapPosition\n");
988 }
989
990
991 /*
992 ================
993 SV_PM_ClampAngles
994 ================
995 */
SV_PM_ClampAngles(void)996 static void SV_PM_ClampAngles (void) {
997 int16 temp;
998
999 if (pm->state.pmFlags & PMF_TIME_TELEPORT) {
1000 pm->viewAngles[YAW] = SHORT2ANGLE (pm->cmd.angles[YAW] + pm->state.deltaAngles[YAW]);
1001 pm->viewAngles[PITCH] = 0;
1002 pm->viewAngles[ROLL] = 0;
1003 }
1004 else {
1005 // circularly clamp the angles with deltas
1006 temp = pm->cmd.angles[0] + pm->state.deltaAngles[0];
1007 pm->viewAngles[0] = SHORT2ANGLE(temp);
1008
1009 temp = pm->cmd.angles[1] + pm->state.deltaAngles[1];
1010 pm->viewAngles[1] = SHORT2ANGLE(temp);
1011
1012 temp = pm->cmd.angles[2] + pm->state.deltaAngles[2];
1013 pm->viewAngles[2] = SHORT2ANGLE(temp);
1014
1015 // don't let the player look up or down more than 90 degrees
1016 if ((pm->viewAngles[PITCH] > 89) && (pm->viewAngles[PITCH] < 180))
1017 pm->viewAngles[PITCH] = 89;
1018 else if ((pm->viewAngles[PITCH] < 271) && (pm->viewAngles[PITCH] >= 180))
1019 pm->viewAngles[PITCH] = 271;
1020 }
1021
1022 Angles_Vectors (pm->viewAngles, pml.forward, pml.right, pml.up);
1023 }
1024
1025
1026 /*
1027 ================
1028 SV_Pmove
1029
1030 Can be called by either the server or the client
1031 ================
1032 */
SV_Pmove(pMoveNew_t * pMove,float airAcceleration)1033 void SV_Pmove (pMoveNew_t *pMove, float airAcceleration) {
1034 pm = pMove;
1035 pmAirAcceleration = airAcceleration;
1036
1037 // clear results
1038 pm->numTouch = 0;
1039 Vec3Clear (pm->viewAngles);
1040 pm->viewHeight = 0;
1041 pm->groundEntity = 0;
1042 pm->waterType = 0;
1043 pm->waterLevel = 0;
1044
1045 // clear all pmove local vars
1046 memset (&pml, 0, sizeof (pml));
1047
1048 // convert origin and velocity to float values
1049 pml.origin[0] = pm->state.origin[0]*(1.0f/8.0f);
1050 pml.origin[1] = pm->state.origin[1]*(1.0f/8.0f);
1051 pml.origin[2] = pm->state.origin[2]*(1.0f/8.0f);
1052
1053 pml.velocity[0] = pm->state.velocity[0]*(1.0f/8.0f);
1054 pml.velocity[1] = pm->state.velocity[1]*(1.0f/8.0f);
1055 pml.velocity[2] = pm->state.velocity[2]*(1.0f/8.0f);
1056
1057 // save old org in case we get stuck
1058 Vec3Copy (pm->state.origin, pml.previousOrigin);
1059
1060 pml.frameTime = pm->cmd.msec * 0.001;
1061
1062 SV_PM_ClampAngles ();
1063
1064 if (pm->state.pmType == PMT_SPECTATOR) {
1065 SV_PM_FlyMove (qFalse);
1066 SV_PM_SnapPosition ();
1067 return;
1068 }
1069
1070 if (pm->state.pmType >= PMT_DEAD) {
1071 pm->cmd.forwardMove = 0;
1072 pm->cmd.sideMove = 0;
1073 pm->cmd.upMove = 0;
1074 }
1075
1076 if (pm->state.pmType == PMT_FREEZE)
1077 return; // no movement at all
1078
1079 // set mins, maxs, and viewHeight
1080 SV_PM_CheckDuck ();
1081
1082 if (pm->snapInitial)
1083 SV_PM_InitialSnapPosition ();
1084
1085 // set groundEntity, waterType, and waterLevel
1086 SV_PM_CatagorizePosition ();
1087
1088 if (pm->state.pmType == PMT_DEAD)
1089 SV_PM_DeadMove ();
1090
1091 SV_PM_CheckSpecialMovement ();
1092
1093 // drop timing counter
1094 if (pm->state.pmTime) {
1095 int msec;
1096
1097 msec = pm->cmd.msec >> 3;
1098 if (!msec)
1099 msec = 1;
1100 if (msec >= pm->state.pmTime) {
1101 pm->state.pmFlags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
1102 pm->state.pmTime = 0;
1103 }
1104 else
1105 pm->state.pmTime -= msec;
1106 }
1107
1108 if (pm->state.pmFlags & PMF_TIME_TELEPORT) {
1109 // teleport pause stays exactly in place
1110 }
1111 else if (pm->state.pmFlags & PMF_TIME_WATERJUMP) {
1112 // waterjump has no control, but falls
1113 pml.velocity[2] -= pm->state.gravity * pml.frameTime;
1114 if (pml.velocity[2] < 0) {
1115 // cancel as soon as we are falling down again
1116 pm->state.pmFlags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
1117 pm->state.pmTime = 0;
1118 }
1119
1120 SV_PM_StepSlideMove ();
1121 }
1122 else {
1123 SV_PM_CheckJump ();
1124
1125 SV_PM_Friction ();
1126
1127 if (pm->waterLevel >= 2)
1128 SV_PM_WaterMove ();
1129 else {
1130 vec3_t angles;
1131
1132 Vec3Copy(pm->viewAngles, angles);
1133 if (angles[PITCH] > 180)
1134 angles[PITCH] = angles[PITCH] - 360;
1135 angles[PITCH] /= 3;
1136
1137 Angles_Vectors (angles, pml.forward, pml.right, pml.up);
1138
1139 SV_PM_AirMove ();
1140 }
1141 }
1142
1143 // set groundEntity, waterType, and waterLevel for final spot
1144 SV_PM_CatagorizePosition ();
1145
1146 SV_PM_SnapPosition ();
1147 }
1148