pmove.c (27381B)
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 80 void PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) 81 { 82 float backoff; 83 float change; 84 int i; 85 86 backoff = DotProduct (in, normal) * overbounce; 87 88 for (i=0 ; i<3 ; i++) 89 { 90 change = normal[i]*backoff; 91 out[i] = in[i] - change; 92 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) 93 out[i] = 0; 94 } 95 } 96 97 98 99 100 /* 101 ================== 102 PM_StepSlideMove 103 104 Each intersection will try to step over the obstruction instead of 105 sliding along it. 106 107 Returns a new origin, velocity, and contact entity 108 Does not modify any world state? 109 ================== 110 */ 111 #define MIN_STEP_NORMAL 0.7 // can't step up onto very steep slopes 112 #define MAX_CLIP_PLANES 5 113 void PM_StepSlideMove_ (void) 114 { 115 int bumpcount, numbumps; 116 vec3_t dir; 117 float d; 118 int numplanes; 119 vec3_t planes[MAX_CLIP_PLANES]; 120 vec3_t primal_velocity; 121 int i, j; 122 trace_t trace; 123 vec3_t end; 124 float time_left; 125 126 numbumps = 4; 127 128 VectorCopy (pml.velocity, primal_velocity); 129 numplanes = 0; 130 131 time_left = pml.frametime; 132 133 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) 134 { 135 for (i=0 ; i<3 ; i++) 136 end[i] = pml.origin[i] + time_left * pml.velocity[i]; 137 138 trace = pm->trace (pml.origin, pm->mins, pm->maxs, end); 139 140 if (trace.allsolid) 141 { // entity is trapped in another solid 142 pml.velocity[2] = 0; // don't build up falling damage 143 return; 144 } 145 146 if (trace.fraction > 0) 147 { // actually covered some distance 148 VectorCopy (trace.endpos, pml.origin); 149 numplanes = 0; 150 } 151 152 if (trace.fraction == 1) 153 break; // moved the entire distance 154 155 // save entity for contact 156 if (pm->numtouch < MAXTOUCH && trace.ent) 157 { 158 pm->touchents[pm->numtouch] = trace.ent; 159 pm->numtouch++; 160 } 161 162 time_left -= time_left * trace.fraction; 163 164 // slide along this plane 165 if (numplanes >= MAX_CLIP_PLANES) 166 { // this shouldn't really happen 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 */ 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 */ 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 */ 397 void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel) 398 { 399 int i; 400 float addspeed, accelspeed, currentspeed; 401 402 currentspeed = DotProduct (pml.velocity, wishdir); 403 addspeed = wishspeed - currentspeed; 404 if (addspeed <= 0) 405 return; 406 accelspeed = accel*pml.frametime*wishspeed; 407 if (accelspeed > addspeed) 408 accelspeed = addspeed; 409 410 for (i=0 ; i<3 ; i++) 411 pml.velocity[i] += accelspeed*wishdir[i]; 412 } 413 414 void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel) 415 { 416 int i; 417 float addspeed, accelspeed, currentspeed, wishspd = wishspeed; 418 419 if (wishspd > 30) 420 wishspd = 30; 421 currentspeed = DotProduct (pml.velocity, wishdir); 422 addspeed = wishspd - currentspeed; 423 if (addspeed <= 0) 424 return; 425 accelspeed = accel * wishspeed * pml.frametime; 426 if (accelspeed > addspeed) 427 accelspeed = addspeed; 428 429 for (i=0 ; i<3 ; i++) 430 pml.velocity[i] += accelspeed*wishdir[i]; 431 } 432 433 /* 434 ============= 435 PM_AddCurrents 436 ============= 437 */ 438 void PM_AddCurrents (vec3_t wishvel) 439 { 440 vec3_t v; 441 float s; 442 443 // 444 // account for ladders 445 // 446 447 if (pml.ladder && fabs(pml.velocity[2]) <= 200) 448 { 449 if ((pm->viewangles[PITCH] <= -15) && (pm->cmd.forwardmove > 0)) 450 wishvel[2] = 200; 451 else if ((pm->viewangles[PITCH] >= 15) && (pm->cmd.forwardmove > 0)) 452 wishvel[2] = -200; 453 else if (pm->cmd.upmove > 0) 454 wishvel[2] = 200; 455 else if (pm->cmd.upmove < 0) 456 wishvel[2] = -200; 457 else 458 wishvel[2] = 0; 459 460 // limit horizontal speed when on a ladder 461 if (wishvel[0] < -25) 462 wishvel[0] = -25; 463 else if (wishvel[0] > 25) 464 wishvel[0] = 25; 465 466 if (wishvel[1] < -25) 467 wishvel[1] = -25; 468 else if (wishvel[1] > 25) 469 wishvel[1] = 25; 470 } 471 472 473 // 474 // add water currents 475 // 476 477 if (pm->watertype & MASK_CURRENT) 478 { 479 VectorClear (v); 480 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 */ 533 void PM_WaterMove (void) 534 { 535 int i; 536 vec3_t wishvel; 537 float wishspeed; 538 vec3_t wishdir; 539 540 // 541 // user intentions 542 // 543 for (i=0 ; i<3 ; i++) 544 wishvel[i] = pml.forward[i]*pm->cmd.forwardmove + pml.right[i]*pm->cmd.sidemove; 545 546 if (!pm->cmd.forwardmove && !pm->cmd.sidemove && !pm->cmd.upmove) 547 wishvel[2] -= 60; // drift towards bottom 548 else 549 wishvel[2] += pm->cmd.upmove; 550 551 PM_AddCurrents (wishvel); 552 553 VectorCopy (wishvel, wishdir); 554 wishspeed = VectorNormalize(wishdir); 555 556 if (wishspeed > pm_maxspeed) 557 { 558 VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel); 559 wishspeed = pm_maxspeed; 560 } 561 wishspeed *= 0.5; 562 563 PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate); 564 565 PM_StepSlideMove (); 566 } 567 568 569 /* 570 =================== 571 PM_AirMove 572 573 =================== 574 */ 575 void PM_AirMove (void) 576 { 577 int i; 578 vec3_t wishvel; 579 float fmove, smove; 580 vec3_t wishdir; 581 float wishspeed; 582 float maxspeed; 583 584 fmove = pm->cmd.forwardmove; 585 smove = pm->cmd.sidemove; 586 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 */ 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 */ 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 */ 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 */ 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 */ 976 void PM_CheckDuck (void) 977 { 978 trace_t trace; 979 980 pm->mins[0] = -16; 981 pm->mins[1] = -16; 982 983 pm->maxs[0] = 16; 984 pm->maxs[1] = 16; 985 986 if (pm->s.pm_type == PM_GIB) 987 { 988 pm->mins[2] = 0; 989 pm->maxs[2] = 16; 990 pm->viewheight = 8; 991 return; 992 } 993 994 pm->mins[2] = -24; 995 996 if (pm->s.pm_type == PM_DEAD) 997 { 998 pm->s.pm_flags |= PMF_DUCKED; 999 } 1000 else if (pm->cmd.upmove < 0 && (pm->s.pm_flags & PMF_ON_GROUND) ) 1001 { // duck 1002 pm->s.pm_flags |= PMF_DUCKED; 1003 } 1004 else 1005 { // stand up if possible 1006 if (pm->s.pm_flags & PMF_DUCKED) 1007 { 1008 // try to stand up 1009 pm->maxs[2] = 32; 1010 trace = pm->trace (pml.origin, pm->mins, pm->maxs, pml.origin); 1011 if (!trace.allsolid) 1012 pm->s.pm_flags &= ~PMF_DUCKED; 1013 } 1014 } 1015 1016 if (pm->s.pm_flags & PMF_DUCKED) 1017 { 1018 pm->maxs[2] = 4; 1019 pm->viewheight = -2; 1020 } 1021 else 1022 { 1023 pm->maxs[2] = 32; 1024 pm->viewheight = 22; 1025 } 1026 } 1027 1028 1029 /* 1030 ============== 1031 PM_DeadMove 1032 ============== 1033 */ 1034 void PM_DeadMove (void) 1035 { 1036 float forward; 1037 1038 if (!pm->groundentity) 1039 return; 1040 1041 // extra friction 1042 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 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 */ 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 */ 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 */ 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 */ 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