g_phys.c (21442B)
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 // g_phys.c 21 22 #include "g_local.h" 23 24 /* 25 26 27 pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move. 28 29 onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects 30 31 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH 32 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS 33 corpses are SOLID_NOT and MOVETYPE_TOSS 34 crates are SOLID_BBOX and MOVETYPE_TOSS 35 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP 36 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY 37 38 solid_edge items only clip against bsp models. 39 40 */ 41 42 43 /* 44 ============ 45 SV_TestEntityPosition 46 47 ============ 48 */ 49 edict_t *SV_TestEntityPosition (edict_t *ent) 50 { 51 trace_t trace; 52 int mask; 53 54 if (ent->clipmask) 55 mask = ent->clipmask; 56 else 57 mask = MASK_SOLID; 58 trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, mask); 59 60 if (trace.startsolid) 61 return g_edicts; 62 63 return NULL; 64 } 65 66 67 /* 68 ================ 69 SV_CheckVelocity 70 ================ 71 */ 72 void SV_CheckVelocity (edict_t *ent) 73 { 74 int i; 75 76 // 77 // bound velocity 78 // 79 for (i=0 ; i<3 ; i++) 80 { 81 if (ent->velocity[i] > sv_maxvelocity->value) 82 ent->velocity[i] = sv_maxvelocity->value; 83 else if (ent->velocity[i] < -sv_maxvelocity->value) 84 ent->velocity[i] = -sv_maxvelocity->value; 85 } 86 } 87 88 /* 89 ============= 90 SV_RunThink 91 92 Runs thinking code for this frame if necessary 93 ============= 94 */ 95 qboolean SV_RunThink (edict_t *ent) 96 { 97 float thinktime; 98 99 thinktime = ent->nextthink; 100 if (thinktime <= 0) 101 return true; 102 if (thinktime > level.time+0.001) 103 return true; 104 105 ent->nextthink = 0; 106 if (!ent->think) 107 gi.error ("NULL ent->think"); 108 ent->think (ent); 109 110 return false; 111 } 112 113 /* 114 ================== 115 SV_Impact 116 117 Two entities have touched, so run their touch functions 118 ================== 119 */ 120 void SV_Impact (edict_t *e1, trace_t *trace) 121 { 122 edict_t *e2; 123 // cplane_t backplane; 124 125 e2 = trace->ent; 126 127 if (e1->touch && e1->solid != SOLID_NOT) 128 e1->touch (e1, e2, &trace->plane, trace->surface); 129 130 if (e2->touch && e2->solid != SOLID_NOT) 131 e2->touch (e2, e1, NULL, NULL); 132 } 133 134 135 /* 136 ================== 137 ClipVelocity 138 139 Slide off of the impacting object 140 returns the blocked flags (1 = floor, 2 = step / wall) 141 ================== 142 */ 143 #define STOP_EPSILON 0.1 144 145 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) 146 { 147 float backoff; 148 float change; 149 int i, blocked; 150 151 blocked = 0; 152 if (normal[2] > 0) 153 blocked |= 1; // floor 154 if (!normal[2]) 155 blocked |= 2; // step 156 157 backoff = DotProduct (in, normal) * overbounce; 158 159 for (i=0 ; i<3 ; i++) 160 { 161 change = normal[i]*backoff; 162 out[i] = in[i] - change; 163 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) 164 out[i] = 0; 165 } 166 167 return blocked; 168 } 169 170 171 /* 172 ============ 173 SV_FlyMove 174 175 The basic solid body movement clip that slides along multiple planes 176 Returns the clipflags if the velocity was modified (hit something solid) 177 1 = floor 178 2 = wall / step 179 4 = dead stop 180 ============ 181 */ 182 #define MAX_CLIP_PLANES 5 183 int SV_FlyMove (edict_t *ent, float time, int mask) 184 { 185 edict_t *hit; 186 int bumpcount, numbumps; 187 vec3_t dir; 188 float d; 189 int numplanes; 190 vec3_t planes[MAX_CLIP_PLANES]; 191 vec3_t primal_velocity, original_velocity, new_velocity; 192 int i, j; 193 trace_t trace; 194 vec3_t end; 195 float time_left; 196 int blocked; 197 198 numbumps = 4; 199 200 blocked = 0; 201 VectorCopy (ent->velocity, original_velocity); 202 VectorCopy (ent->velocity, primal_velocity); 203 numplanes = 0; 204 205 time_left = time; 206 207 ent->groundentity = NULL; 208 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) 209 { 210 for (i=0 ; i<3 ; i++) 211 end[i] = ent->s.origin[i] + time_left * ent->velocity[i]; 212 213 trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask); 214 215 if (trace.allsolid) 216 { // entity is trapped in another solid 217 VectorCopy (vec3_origin, ent->velocity); 218 return 3; 219 } 220 221 if (trace.fraction > 0) 222 { // actually covered some distance 223 VectorCopy (trace.endpos, ent->s.origin); 224 VectorCopy (ent->velocity, original_velocity); 225 numplanes = 0; 226 } 227 228 if (trace.fraction == 1) 229 break; // moved the entire distance 230 231 hit = trace.ent; 232 233 if (trace.plane.normal[2] > 0.7) 234 { 235 blocked |= 1; // floor 236 if ( hit->solid == SOLID_BSP) 237 { 238 ent->groundentity = hit; 239 ent->groundentity_linkcount = hit->linkcount; 240 } 241 } 242 if (!trace.plane.normal[2]) 243 { 244 blocked |= 2; // step 245 } 246 247 // 248 // run the impact function 249 // 250 SV_Impact (ent, &trace); 251 if (!ent->inuse) 252 break; // removed by the impact function 253 254 255 time_left -= time_left * trace.fraction; 256 257 // cliped to another plane 258 if (numplanes >= MAX_CLIP_PLANES) 259 { // this shouldn't really happen 260 VectorCopy (vec3_origin, ent->velocity); 261 return 3; 262 } 263 264 VectorCopy (trace.plane.normal, planes[numplanes]); 265 numplanes++; 266 267 // 268 // modify original_velocity so it parallels all of the clip planes 269 // 270 for (i=0 ; i<numplanes ; i++) 271 { 272 ClipVelocity (original_velocity, planes[i], new_velocity, 1); 273 274 for (j=0 ; j<numplanes ; j++) 275 if ((j != i) && !VectorCompare (planes[i], planes[j])) 276 { 277 if (DotProduct (new_velocity, planes[j]) < 0) 278 break; // not ok 279 } 280 if (j == numplanes) 281 break; 282 } 283 284 if (i != numplanes) 285 { // go along this plane 286 VectorCopy (new_velocity, ent->velocity); 287 } 288 else 289 { // go along the crease 290 if (numplanes != 2) 291 { 292 // gi.dprintf ("clip velocity, numplanes == %i\n",numplanes); 293 VectorCopy (vec3_origin, ent->velocity); 294 return 7; 295 } 296 CrossProduct (planes[0], planes[1], dir); 297 d = DotProduct (dir, ent->velocity); 298 VectorScale (dir, d, ent->velocity); 299 } 300 301 // 302 // if original velocity is against the original velocity, stop dead 303 // to avoid tiny occilations in sloping corners 304 // 305 if (DotProduct (ent->velocity, primal_velocity) <= 0) 306 { 307 VectorCopy (vec3_origin, ent->velocity); 308 return blocked; 309 } 310 } 311 312 return blocked; 313 } 314 315 316 /* 317 ============ 318 SV_AddGravity 319 320 ============ 321 */ 322 void SV_AddGravity (edict_t *ent) 323 { 324 ent->velocity[2] -= ent->gravity * sv_gravity->value * FRAMETIME; 325 } 326 327 /* 328 =============================================================================== 329 330 PUSHMOVE 331 332 =============================================================================== 333 */ 334 335 /* 336 ============ 337 SV_PushEntity 338 339 Does not change the entities velocity at all 340 ============ 341 */ 342 trace_t SV_PushEntity (edict_t *ent, vec3_t push) 343 { 344 trace_t trace; 345 vec3_t start; 346 vec3_t end; 347 int mask; 348 349 VectorCopy (ent->s.origin, start); 350 VectorAdd (start, push, end); 351 352 retry: 353 if (ent->clipmask) 354 mask = ent->clipmask; 355 else 356 mask = MASK_SOLID; 357 358 trace = gi.trace (start, ent->mins, ent->maxs, end, ent, mask); 359 360 VectorCopy (trace.endpos, ent->s.origin); 361 gi.linkentity (ent); 362 363 if (trace.fraction != 1.0) 364 { 365 SV_Impact (ent, &trace); 366 367 // if the pushed entity went away and the pusher is still there 368 if (!trace.ent->inuse && ent->inuse) 369 { 370 // move the pusher back and try again 371 VectorCopy (start, ent->s.origin); 372 gi.linkentity (ent); 373 goto retry; 374 } 375 } 376 377 if (ent->inuse) 378 G_TouchTriggers (ent); 379 380 return trace; 381 } 382 383 384 typedef struct 385 { 386 edict_t *ent; 387 vec3_t origin; 388 vec3_t angles; 389 float deltayaw; 390 } pushed_t; 391 pushed_t pushed[MAX_EDICTS], *pushed_p; 392 393 edict_t *obstacle; 394 395 /* 396 ============ 397 SV_Push 398 399 Objects need to be moved back on a failed push, 400 otherwise riders would continue to slide. 401 ============ 402 */ 403 qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) 404 { 405 int i, e; 406 edict_t *check, *block; 407 vec3_t mins, maxs; 408 pushed_t *p; 409 vec3_t org, org2, move2, forward, right, up; 410 411 // clamp the move to 1/8 units, so the position will 412 // be accurate for client side prediction 413 for (i=0 ; i<3 ; i++) 414 { 415 float temp; 416 temp = move[i]*8.0; 417 if (temp > 0.0) 418 temp += 0.5; 419 else 420 temp -= 0.5; 421 move[i] = 0.125 * (int)temp; 422 } 423 424 // find the bounding box 425 for (i=0 ; i<3 ; i++) 426 { 427 mins[i] = pusher->absmin[i] + move[i]; 428 maxs[i] = pusher->absmax[i] + move[i]; 429 } 430 431 // we need this for pushing things later 432 VectorSubtract (vec3_origin, amove, org); 433 AngleVectors (org, forward, right, up); 434 435 // save the pusher's original position 436 pushed_p->ent = pusher; 437 VectorCopy (pusher->s.origin, pushed_p->origin); 438 VectorCopy (pusher->s.angles, pushed_p->angles); 439 if (pusher->client) 440 pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW]; 441 pushed_p++; 442 443 // move the pusher to it's final position 444 VectorAdd (pusher->s.origin, move, pusher->s.origin); 445 VectorAdd (pusher->s.angles, amove, pusher->s.angles); 446 gi.linkentity (pusher); 447 448 // see if any solid entities are inside the final position 449 check = g_edicts+1; 450 for (e = 1; e < globals.num_edicts; e++, check++) 451 { 452 if (!check->inuse) 453 continue; 454 if (check->movetype == MOVETYPE_PUSH 455 || check->movetype == MOVETYPE_STOP 456 || check->movetype == MOVETYPE_NONE 457 || check->movetype == MOVETYPE_NOCLIP) 458 continue; 459 460 if (!check->area.prev) 461 continue; // not linked in anywhere 462 463 // if the entity is standing on the pusher, it will definitely be moved 464 if (check->groundentity != pusher) 465 { 466 // see if the ent needs to be tested 467 if ( check->absmin[0] >= maxs[0] 468 || check->absmin[1] >= maxs[1] 469 || check->absmin[2] >= maxs[2] 470 || check->absmax[0] <= mins[0] 471 || check->absmax[1] <= mins[1] 472 || check->absmax[2] <= mins[2] ) 473 continue; 474 475 // see if the ent's bbox is inside the pusher's final position 476 if (!SV_TestEntityPosition (check)) 477 continue; 478 } 479 480 if ((pusher->movetype == MOVETYPE_PUSH) || (check->groundentity == pusher)) 481 { 482 // move this entity 483 pushed_p->ent = check; 484 VectorCopy (check->s.origin, pushed_p->origin); 485 VectorCopy (check->s.angles, pushed_p->angles); 486 pushed_p++; 487 488 // try moving the contacted entity 489 VectorAdd (check->s.origin, move, check->s.origin); 490 if (check->client) 491 { // FIXME: doesn't rotate monsters? 492 check->client->ps.pmove.delta_angles[YAW] += amove[YAW]; 493 } 494 495 // figure movement due to the pusher's amove 496 VectorSubtract (check->s.origin, pusher->s.origin, org); 497 org2[0] = DotProduct (org, forward); 498 org2[1] = -DotProduct (org, right); 499 org2[2] = DotProduct (org, up); 500 VectorSubtract (org2, org, move2); 501 VectorAdd (check->s.origin, move2, check->s.origin); 502 503 // may have pushed them off an edge 504 if (check->groundentity != pusher) 505 check->groundentity = NULL; 506 507 block = SV_TestEntityPosition (check); 508 if (!block) 509 { // pushed ok 510 gi.linkentity (check); 511 // impact? 512 continue; 513 } 514 515 // if it is ok to leave in the old position, do it 516 // this is only relevent for riding entities, not pushed 517 // FIXME: this doesn't acount for rotation 518 VectorSubtract (check->s.origin, move, check->s.origin); 519 block = SV_TestEntityPosition (check); 520 if (!block) 521 { 522 pushed_p--; 523 continue; 524 } 525 } 526 527 // save off the obstacle so we can call the block function 528 obstacle = check; 529 530 // move back any entities we already moved 531 // go backwards, so if the same entity was pushed 532 // twice, it goes back to the original position 533 for (p=pushed_p-1 ; p>=pushed ; p--) 534 { 535 VectorCopy (p->origin, p->ent->s.origin); 536 VectorCopy (p->angles, p->ent->s.angles); 537 if (p->ent->client) 538 { 539 p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw; 540 } 541 gi.linkentity (p->ent); 542 } 543 return false; 544 } 545 546 //FIXME: is there a better way to handle this? 547 // see if anything we moved has touched a trigger 548 for (p=pushed_p-1 ; p>=pushed ; p--) 549 G_TouchTriggers (p->ent); 550 551 return true; 552 } 553 554 /* 555 ================ 556 SV_Physics_Pusher 557 558 Bmodel objects don't interact with each other, but 559 push all box objects 560 ================ 561 */ 562 void SV_Physics_Pusher (edict_t *ent) 563 { 564 vec3_t move, amove; 565 edict_t *part, *mv; 566 567 // if not a team captain, so movement will be handled elsewhere 568 if ( ent->flags & FL_TEAMSLAVE) 569 return; 570 571 // make sure all team slaves can move before commiting 572 // any moves or calling any think functions 573 // if the move is blocked, all moved objects will be backed out 574 //retry: 575 pushed_p = pushed; 576 for (part = ent ; part ; part=part->teamchain) 577 { 578 if (part->velocity[0] || part->velocity[1] || part->velocity[2] || 579 part->avelocity[0] || part->avelocity[1] || part->avelocity[2] 580 ) 581 { // object is moving 582 VectorScale (part->velocity, FRAMETIME, move); 583 VectorScale (part->avelocity, FRAMETIME, amove); 584 585 if (!SV_Push (part, move, amove)) 586 break; // move was blocked 587 } 588 } 589 if (pushed_p > &pushed[MAX_EDICTS]) 590 gi.error (ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted"); 591 592 if (part) 593 { 594 // the move failed, bump all nextthink times and back out moves 595 for (mv = ent ; mv ; mv=mv->teamchain) 596 { 597 if (mv->nextthink > 0) 598 mv->nextthink += FRAMETIME; 599 } 600 601 // if the pusher has a "blocked" function, call it 602 // otherwise, just stay in place until the obstacle is gone 603 if (part->blocked) 604 part->blocked (part, obstacle); 605 #if 0 606 // if the pushed entity went away and the pusher is still there 607 if (!obstacle->inuse && part->inuse) 608 goto retry; 609 #endif 610 } 611 else 612 { 613 // the move succeeded, so call all think functions 614 for (part = ent ; part ; part=part->teamchain) 615 { 616 SV_RunThink (part); 617 } 618 } 619 } 620 621 //================================================================== 622 623 /* 624 ============= 625 SV_Physics_None 626 627 Non moving objects can only think 628 ============= 629 */ 630 void SV_Physics_None (edict_t *ent) 631 { 632 // regular thinking 633 SV_RunThink (ent); 634 } 635 636 /* 637 ============= 638 SV_Physics_Noclip 639 640 A moving object that doesn't obey physics 641 ============= 642 */ 643 void SV_Physics_Noclip (edict_t *ent) 644 { 645 // regular thinking 646 if (!SV_RunThink (ent)) 647 return; 648 649 VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); 650 VectorMA (ent->s.origin, FRAMETIME, ent->velocity, ent->s.origin); 651 652 gi.linkentity (ent); 653 } 654 655 /* 656 ============================================================================== 657 658 TOSS / BOUNCE 659 660 ============================================================================== 661 */ 662 663 /* 664 ============= 665 SV_Physics_Toss 666 667 Toss, bounce, and fly movement. When onground, do nothing. 668 ============= 669 */ 670 void SV_Physics_Toss (edict_t *ent) 671 { 672 trace_t trace; 673 vec3_t move; 674 float backoff; 675 edict_t *slave; 676 qboolean wasinwater; 677 qboolean isinwater; 678 vec3_t old_origin; 679 680 // regular thinking 681 SV_RunThink (ent); 682 683 // if not a team captain, so movement will be handled elsewhere 684 if ( ent->flags & FL_TEAMSLAVE) 685 return; 686 687 if (ent->velocity[2] > 0) 688 ent->groundentity = NULL; 689 690 // check for the groundentity going away 691 if (ent->groundentity) 692 if (!ent->groundentity->inuse) 693 ent->groundentity = NULL; 694 695 // if onground, return without moving 696 if ( ent->groundentity ) 697 return; 698 699 VectorCopy (ent->s.origin, old_origin); 700 701 SV_CheckVelocity (ent); 702 703 // add gravity 704 if (ent->movetype != MOVETYPE_FLY 705 && ent->movetype != MOVETYPE_FLYMISSILE) 706 SV_AddGravity (ent); 707 708 // move angles 709 VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); 710 711 // move origin 712 VectorScale (ent->velocity, FRAMETIME, move); 713 trace = SV_PushEntity (ent, move); 714 if (!ent->inuse) 715 return; 716 717 if (trace.fraction < 1) 718 { 719 if (ent->movetype == MOVETYPE_BOUNCE) 720 backoff = 1.5; 721 else 722 backoff = 1; 723 724 ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff); 725 726 // stop if on ground 727 if (trace.plane.normal[2] > 0.7) 728 { 729 if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE ) 730 { 731 ent->groundentity = trace.ent; 732 ent->groundentity_linkcount = trace.ent->linkcount; 733 VectorCopy (vec3_origin, ent->velocity); 734 VectorCopy (vec3_origin, ent->avelocity); 735 } 736 } 737 738 // if (ent->touch) 739 // ent->touch (ent, trace.ent, &trace.plane, trace.surface); 740 } 741 742 // check for water transition 743 wasinwater = (ent->watertype & MASK_WATER); 744 ent->watertype = gi.pointcontents (ent->s.origin); 745 isinwater = ent->watertype & MASK_WATER; 746 747 if (isinwater) 748 ent->waterlevel = 1; 749 else 750 ent->waterlevel = 0; 751 752 if (!wasinwater && isinwater) 753 gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); 754 else if (wasinwater && !isinwater) 755 gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); 756 757 // move teamslaves 758 for (slave = ent->teamchain; slave; slave = slave->teamchain) 759 { 760 VectorCopy (ent->s.origin, slave->s.origin); 761 gi.linkentity (slave); 762 } 763 } 764 765 /* 766 =============================================================================== 767 768 STEPPING MOVEMENT 769 770 =============================================================================== 771 */ 772 773 /* 774 ============= 775 SV_Physics_Step 776 777 Monsters freefall when they don't have a ground entity, otherwise 778 all movement is done with discrete steps. 779 780 This is also used for objects that have become still on the ground, but 781 will fall if the floor is pulled out from under them. 782 FIXME: is this true? 783 ============= 784 */ 785 786 //FIXME: hacked in for E3 demo 787 #define sv_stopspeed 100 788 #define sv_friction 6 789 #define sv_waterfriction 1 790 791 void SV_AddRotationalFriction (edict_t *ent) 792 { 793 int n; 794 float adjustment; 795 796 VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); 797 adjustment = FRAMETIME * sv_stopspeed * sv_friction; 798 for (n = 0; n < 3; n++) 799 { 800 if (ent->avelocity[n] > 0) 801 { 802 ent->avelocity[n] -= adjustment; 803 if (ent->avelocity[n] < 0) 804 ent->avelocity[n] = 0; 805 } 806 else 807 { 808 ent->avelocity[n] += adjustment; 809 if (ent->avelocity[n] > 0) 810 ent->avelocity[n] = 0; 811 } 812 } 813 } 814 815 void SV_Physics_Step (edict_t *ent) 816 { 817 qboolean wasonground; 818 qboolean hitsound = false; 819 float *vel; 820 float speed, newspeed, control; 821 float friction; 822 edict_t *groundentity; 823 int mask; 824 825 // airborn monsters should always check for ground 826 if (!ent->groundentity) 827 M_CheckGround (ent); 828 829 groundentity = ent->groundentity; 830 831 SV_CheckVelocity (ent); 832 833 if (groundentity) 834 wasonground = true; 835 else 836 wasonground = false; 837 838 if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) 839 SV_AddRotationalFriction (ent); 840 841 // add gravity except: 842 // flying monsters 843 // swimming monsters who are in the water 844 if (! wasonground) 845 if (!(ent->flags & FL_FLY)) 846 if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) 847 { 848 if (ent->velocity[2] < sv_gravity->value*-0.1) 849 hitsound = true; 850 if (ent->waterlevel == 0) 851 SV_AddGravity (ent); 852 } 853 854 // friction for flying monsters that have been given vertical velocity 855 if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) 856 { 857 speed = fabs(ent->velocity[2]); 858 control = speed < sv_stopspeed ? sv_stopspeed : speed; 859 friction = sv_friction/3; 860 newspeed = speed - (FRAMETIME * control * friction); 861 if (newspeed < 0) 862 newspeed = 0; 863 newspeed /= speed; 864 ent->velocity[2] *= newspeed; 865 } 866 867 // friction for flying monsters that have been given vertical velocity 868 if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) 869 { 870 speed = fabs(ent->velocity[2]); 871 control = speed < sv_stopspeed ? sv_stopspeed : speed; 872 newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel); 873 if (newspeed < 0) 874 newspeed = 0; 875 newspeed /= speed; 876 ent->velocity[2] *= newspeed; 877 } 878 879 if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) 880 { 881 // apply friction 882 // let dead monsters who aren't completely onground slide 883 if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY))) 884 if (!(ent->health <= 0.0 && !M_CheckBottom(ent))) 885 { 886 vel = ent->velocity; 887 speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); 888 if (speed) 889 { 890 friction = sv_friction; 891 892 control = speed < sv_stopspeed ? sv_stopspeed : speed; 893 newspeed = speed - FRAMETIME*control*friction; 894 895 if (newspeed < 0) 896 newspeed = 0; 897 newspeed /= speed; 898 899 vel[0] *= newspeed; 900 vel[1] *= newspeed; 901 } 902 } 903 904 if (ent->svflags & SVF_MONSTER) 905 mask = MASK_MONSTERSOLID; 906 else 907 mask = MASK_SOLID; 908 SV_FlyMove (ent, FRAMETIME, mask); 909 910 gi.linkentity (ent); 911 G_TouchTriggers (ent); 912 if (!ent->inuse) 913 return; 914 915 if (ent->groundentity) 916 if (!wasonground) 917 if (hitsound) 918 gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0); 919 } 920 921 // regular thinking 922 SV_RunThink (ent); 923 } 924 925 //============================================================================ 926 /* 927 ================ 928 G_RunEntity 929 930 ================ 931 */ 932 void G_RunEntity (edict_t *ent) 933 { 934 if (ent->prethink) 935 ent->prethink (ent); 936 937 switch ( (int)ent->movetype) 938 { 939 case MOVETYPE_PUSH: 940 case MOVETYPE_STOP: 941 SV_Physics_Pusher (ent); 942 break; 943 case MOVETYPE_NONE: 944 SV_Physics_None (ent); 945 break; 946 case MOVETYPE_NOCLIP: 947 SV_Physics_Noclip (ent); 948 break; 949 case MOVETYPE_STEP: 950 SV_Physics_Step (ent); 951 break; 952 case MOVETYPE_TOSS: 953 case MOVETYPE_BOUNCE: 954 case MOVETYPE_FLY: 955 case MOVETYPE_FLYMISSILE: 956 SV_Physics_Toss (ent); 957 break; 958 default: 959 gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype); 960 } 961 }