1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19*/ 20// sv_phys.c 21 22#include "qwsvdef.h" 23 24/* 25 26 27pushmove 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 29onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects 30 31doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH 32bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS 33corpses are SOLID_NOT and MOVETYPE_TOSS 34crates are SOLID_BBOX and MOVETYPE_TOSS 35walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP 36flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY 37 38solid_edge items only clip against bsp models. 39 40*/ 41 42cvar_t sv_maxvelocity = {"sv_maxvelocity","2000"}; 43 44cvar_t sv_gravity = { "sv_gravity", "800"}; 45cvar_t sv_stopspeed = { "sv_stopspeed", "100"}; 46cvar_t sv_maxspeed = { "sv_maxspeed", "320"}; 47cvar_t sv_spectatormaxspeed = { "sv_spectatormaxspeed", "500"}; 48cvar_t sv_accelerate = { "sv_accelerate", "10"}; 49cvar_t sv_airaccelerate = { "sv_airaccelerate", "0.7"}; 50cvar_t sv_wateraccelerate = { "sv_wateraccelerate", "10"}; 51cvar_t sv_friction = { "sv_friction", "4"}; 52cvar_t sv_waterfriction = { "sv_waterfriction", "4"}; 53 54 55#define MOVE_EPSILON 0.01 56 57void SV_Physics_Toss (edict_t *ent); 58 59/* 60================ 61SV_CheckAllEnts 62================ 63*/ 64void SV_CheckAllEnts (void) 65{ 66 int e; 67 edict_t *check; 68 69// see if any solid entities are inside the final position 70 check = NEXT_EDICT(sv.edicts); 71 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) 72 { 73 if (check->free) 74 continue; 75 if (check->v.movetype == MOVETYPE_PUSH 76 || check->v.movetype == MOVETYPE_NONE 77 || check->v.movetype == MOVETYPE_NOCLIP) 78 continue; 79 80 if (SV_TestEntityPosition (check)) 81 Con_Printf ("entity in invalid position\n"); 82 } 83} 84 85/* 86================ 87SV_CheckVelocity 88================ 89*/ 90void SV_CheckVelocity (edict_t *ent) 91{ 92 int i; 93 94// 95// bound velocity 96// 97 for (i=0 ; i<3 ; i++) 98 { 99 if (IS_NAN(ent->v.velocity[i])) 100 { 101 Con_Printf ("Got a NaN velocity on %s\n", PR_GetString(ent->v.classname)); 102 ent->v.velocity[i] = 0; 103 } 104 if (IS_NAN(ent->v.origin[i])) 105 { 106 Con_Printf ("Got a NaN origin on %s\n", PR_GetString(ent->v.classname)); 107 ent->v.origin[i] = 0; 108 } 109 if (ent->v.velocity[i] > sv_maxvelocity.value) 110 ent->v.velocity[i] = sv_maxvelocity.value; 111 else if (ent->v.velocity[i] < -sv_maxvelocity.value) 112 ent->v.velocity[i] = -sv_maxvelocity.value; 113 } 114} 115 116/* 117============= 118SV_RunThink 119 120Runs thinking code if time. There is some play in the exact time the think 121function will be called, because it is called before any movement is done 122in a frame. Not used for pushmove objects, because they must be exact. 123Returns false if the entity removed itself. 124============= 125*/ 126qboolean SV_RunThink (edict_t *ent) 127{ 128 float thinktime; 129 130 do 131 { 132 thinktime = ent->v.nextthink; 133 if (thinktime <= 0) 134 return true; 135 if (thinktime > sv.time + host_frametime) 136 return true; 137 138 if (thinktime < sv.time) 139 thinktime = sv.time; // don't let things stay in the past. 140 // it is possible to start that way 141 // by a trigger with a local time. 142 ent->v.nextthink = 0; 143 pr_global_struct->time = thinktime; 144 pr_global_struct->self = EDICT_TO_PROG(ent); 145 pr_global_struct->other = EDICT_TO_PROG(sv.edicts); 146 PR_ExecuteProgram (ent->v.think); 147 148 if (ent->free) 149 return false; 150 } while (1); 151 152 return true; 153} 154 155/* 156================== 157SV_Impact 158 159Two entities have touched, so run their touch functions 160================== 161*/ 162void SV_Impact (edict_t *e1, edict_t *e2) 163{ 164 int old_self, old_other; 165 166 old_self = pr_global_struct->self; 167 old_other = pr_global_struct->other; 168 169 pr_global_struct->time = sv.time; 170 if (e1->v.touch && e1->v.solid != SOLID_NOT) 171 { 172 pr_global_struct->self = EDICT_TO_PROG(e1); 173 pr_global_struct->other = EDICT_TO_PROG(e2); 174 PR_ExecuteProgram (e1->v.touch); 175 } 176 177 if (e2->v.touch && e2->v.solid != SOLID_NOT) 178 { 179 pr_global_struct->self = EDICT_TO_PROG(e2); 180 pr_global_struct->other = EDICT_TO_PROG(e1); 181 PR_ExecuteProgram (e2->v.touch); 182 } 183 184 pr_global_struct->self = old_self; 185 pr_global_struct->other = old_other; 186} 187 188 189/* 190================== 191ClipVelocity 192 193Slide off of the impacting object 194returns the blocked flags (1 = floor, 2 = step / wall) 195================== 196*/ 197#define STOP_EPSILON 0.1 198 199int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) 200{ 201 float backoff; 202 float change; 203 int i, blocked; 204 205 blocked = 0; 206 if (normal[2] > 0) 207 blocked |= 1; // floor 208 if (!normal[2]) 209 blocked |= 2; // step 210 211 backoff = DotProduct (in, normal) * overbounce; 212 213 for (i=0 ; i<3 ; i++) 214 { 215 change = normal[i]*backoff; 216 out[i] = in[i] - change; 217 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) 218 out[i] = 0; 219 } 220 221 return blocked; 222} 223 224 225/* 226============ 227SV_FlyMove 228 229The basic solid body movement clip that slides along multiple planes 230Returns the clipflags if the velocity was modified (hit something solid) 2311 = floor 2322 = wall / step 2334 = dead stop 234If steptrace is not NULL, the trace of any vertical wall hit will be stored 235============ 236*/ 237#define MAX_CLIP_PLANES 5 238int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) 239{ 240 int bumpcount, numbumps; 241 vec3_t dir; 242 float d; 243 int numplanes; 244 vec3_t planes[MAX_CLIP_PLANES]; 245 vec3_t primal_velocity, original_velocity, new_velocity; 246 int i, j; 247 trace_t trace; 248 vec3_t end; 249 float time_left; 250 int blocked; 251 252 numbumps = 4; 253 254 blocked = 0; 255 VectorCopy (ent->v.velocity, original_velocity); 256 VectorCopy (ent->v.velocity, primal_velocity); 257 numplanes = 0; 258 259 time_left = time; 260 261 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) 262 { 263 for (i=0 ; i<3 ; i++) 264 end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i]; 265 266 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent); 267 268 if (trace.allsolid) 269 { // entity is trapped in another solid 270 VectorCopy (vec3_origin, ent->v.velocity); 271 return 3; 272 } 273 274 if (trace.fraction > 0) 275 { // actually covered some distance 276 VectorCopy (trace.endpos, ent->v.origin); 277 VectorCopy (ent->v.velocity, original_velocity); 278 numplanes = 0; 279 } 280 281 if (trace.fraction == 1) 282 break; // moved the entire distance 283 284 if (!trace.ent) 285 SV_Error ("SV_FlyMove: !trace.ent"); 286 287 if (trace.plane.normal[2] > 0.7) 288 { 289 blocked |= 1; // floor 290 if (trace.ent->v.solid == SOLID_BSP) 291 { 292 ent->v.flags = (int)ent->v.flags | FL_ONGROUND; 293 ent->v.groundentity = EDICT_TO_PROG(trace.ent); 294 } 295 } 296 if (!trace.plane.normal[2]) 297 { 298 blocked |= 2; // step 299 if (steptrace) 300 *steptrace = trace; // save for player extrafriction 301 } 302 303// 304// run the impact function 305// 306 SV_Impact (ent, trace.ent); 307 if (ent->free) 308 break; // removed by the impact function 309 310 311 time_left -= time_left * trace.fraction; 312 313 // cliped to another plane 314 if (numplanes >= MAX_CLIP_PLANES) 315 { // this shouldn't really happen 316 VectorCopy (vec3_origin, ent->v.velocity); 317 return 3; 318 } 319 320 VectorCopy (trace.plane.normal, planes[numplanes]); 321 numplanes++; 322 323// 324// modify original_velocity so it parallels all of the clip planes 325// 326 for (i=0 ; i<numplanes ; i++) 327 { 328 ClipVelocity (original_velocity, planes[i], new_velocity, 1); 329 for (j=0 ; j<numplanes ; j++) 330 if (j != i) 331 { 332 if (DotProduct (new_velocity, planes[j]) < 0) 333 break; // not ok 334 } 335 if (j == numplanes) 336 break; 337 } 338 339 if (i != numplanes) 340 { // go along this plane 341 VectorCopy (new_velocity, ent->v.velocity); 342 } 343 else 344 { // go along the crease 345 if (numplanes != 2) 346 { 347// Con_Printf ("clip velocity, numplanes == %i\n",numplanes); 348 VectorCopy (vec3_origin, ent->v.velocity); 349 return 7; 350 } 351 CrossProduct (planes[0], planes[1], dir); 352 d = DotProduct (dir, ent->v.velocity); 353 VectorScale (dir, d, ent->v.velocity); 354 } 355 356// 357// if original velocity is against the original velocity, stop dead 358// to avoid tiny occilations in sloping corners 359// 360 if (DotProduct (ent->v.velocity, primal_velocity) <= 0) 361 { 362 VectorCopy (vec3_origin, ent->v.velocity); 363 return blocked; 364 } 365 } 366 367 return blocked; 368} 369 370 371/* 372============ 373SV_AddGravity 374 375============ 376*/ 377void SV_AddGravity (edict_t *ent, float scale) 378{ 379 ent->v.velocity[2] -= scale * movevars.gravity * host_frametime; 380} 381 382/* 383=============================================================================== 384 385PUSHMOVE 386 387=============================================================================== 388*/ 389 390/* 391============ 392SV_PushEntity 393 394Does not change the entities velocity at all 395============ 396*/ 397trace_t SV_PushEntity (edict_t *ent, vec3_t push) 398{ 399 trace_t trace; 400 vec3_t end; 401 402 VectorAdd (ent->v.origin, push, end); 403 404 if (ent->v.movetype == MOVETYPE_FLYMISSILE) 405 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent); 406 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT) 407 // only clip against bmodels 408 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent); 409 else 410 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); 411 412 VectorCopy (trace.endpos, ent->v.origin); 413 SV_LinkEdict (ent, true); 414 415 if (trace.ent) 416 SV_Impact (ent, trace.ent); 417 418 return trace; 419} 420 421 422/* 423============ 424SV_Push 425 426============ 427*/ 428qboolean SV_Push (edict_t *pusher, vec3_t move) 429{ 430 int i, e; 431 edict_t *check, *block; 432 vec3_t mins, maxs; 433 vec3_t pushorig; 434 int num_moved; 435 edict_t *moved_edict[MAX_EDICTS]; 436 vec3_t moved_from[MAX_EDICTS]; 437 438 for (i=0 ; i<3 ; i++) 439 { 440 mins[i] = pusher->v.absmin[i] + move[i]; 441 maxs[i] = pusher->v.absmax[i] + move[i]; 442 } 443 444 VectorCopy (pusher->v.origin, pushorig); 445 446// move the pusher to it's final position 447 448 VectorAdd (pusher->v.origin, move, pusher->v.origin); 449 SV_LinkEdict (pusher, false); 450 451// see if any solid entities are inside the final position 452 num_moved = 0; 453 check = NEXT_EDICT(sv.edicts); 454 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) 455 { 456 if (check->free) 457 continue; 458 if (check->v.movetype == MOVETYPE_PUSH 459 || check->v.movetype == MOVETYPE_NONE 460 || check->v.movetype == MOVETYPE_NOCLIP) 461 continue; 462 463 pusher->v.solid = SOLID_NOT; 464 block = SV_TestEntityPosition (check); 465 pusher->v.solid = SOLID_BSP; 466 if (block) 467 continue; 468 469 // if the entity is standing on the pusher, it will definately be moved 470 if ( ! ( ((int)check->v.flags & FL_ONGROUND) 471 && PROG_TO_EDICT(check->v.groundentity) == pusher) ) 472 { 473 if ( check->v.absmin[0] >= maxs[0] 474 || check->v.absmin[1] >= maxs[1] 475 || check->v.absmin[2] >= maxs[2] 476 || check->v.absmax[0] <= mins[0] 477 || check->v.absmax[1] <= mins[1] 478 || check->v.absmax[2] <= mins[2] ) 479 continue; 480 481 // see if the ent's bbox is inside the pusher's final position 482 if (!SV_TestEntityPosition (check)) 483 continue; 484 } 485 486 VectorCopy (check->v.origin, moved_from[num_moved]); 487 moved_edict[num_moved] = check; 488 num_moved++; 489 490 // try moving the contacted entity 491 VectorAdd (check->v.origin, move, check->v.origin); 492 block = SV_TestEntityPosition (check); 493 if (!block) 494 { // pushed ok 495 SV_LinkEdict (check, false); 496 continue; 497 } 498 499 // if it is ok to leave in the old position, do it 500 VectorSubtract (check->v.origin, move, check->v.origin); 501 block = SV_TestEntityPosition (check); 502 if (!block) 503 { 504 num_moved--; 505 continue; 506 } 507 508 // if it is still inside the pusher, block 509 if (check->v.mins[0] == check->v.maxs[0]) 510 { 511 SV_LinkEdict (check, false); 512 continue; 513 } 514 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) 515 { // corpse 516 check->v.mins[0] = check->v.mins[1] = 0; 517 VectorCopy (check->v.mins, check->v.maxs); 518 SV_LinkEdict (check, false); 519 continue; 520 } 521 522 VectorCopy (pushorig, pusher->v.origin); 523 SV_LinkEdict (pusher, false); 524 525 // if the pusher has a "blocked" function, call it 526 // otherwise, just stay in place until the obstacle is gone 527 if (pusher->v.blocked) 528 { 529 pr_global_struct->self = EDICT_TO_PROG(pusher); 530 pr_global_struct->other = EDICT_TO_PROG(check); 531 PR_ExecuteProgram (pusher->v.blocked); 532 } 533 534 // move back any entities we already moved 535 for (i=0 ; i<num_moved ; i++) 536 { 537 VectorCopy (moved_from[i], moved_edict[i]->v.origin); 538 SV_LinkEdict (moved_edict[i], false); 539 } 540 return false; 541 } 542 543 return true; 544} 545 546/* 547============ 548SV_PushMove 549 550============ 551*/ 552void SV_PushMove (edict_t *pusher, float movetime) 553{ 554 int i; 555 vec3_t move; 556 557 if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) 558 { 559 pusher->v.ltime += movetime; 560 return; 561 } 562 563 for (i=0 ; i<3 ; i++) 564 move[i] = pusher->v.velocity[i] * movetime; 565 566 if (SV_Push (pusher, move)) 567 pusher->v.ltime += movetime; 568} 569 570 571/* 572================ 573SV_Physics_Pusher 574 575================ 576*/ 577void SV_Physics_Pusher (edict_t *ent) 578{ 579 float thinktime; 580 float oldltime; 581 float movetime; 582vec3_t oldorg, move; 583float l; 584 585 oldltime = ent->v.ltime; 586 587 thinktime = ent->v.nextthink; 588 if (thinktime < ent->v.ltime + host_frametime) 589 { 590 movetime = thinktime - ent->v.ltime; 591 if (movetime < 0) 592 movetime = 0; 593 } 594 else 595 movetime = host_frametime; 596 597 if (movetime) 598 { 599 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked 600 } 601 602 if (thinktime > oldltime && thinktime <= ent->v.ltime) 603 { 604VectorCopy (ent->v.origin, oldorg); 605 ent->v.nextthink = 0; 606 pr_global_struct->time = sv.time; 607 pr_global_struct->self = EDICT_TO_PROG(ent); 608 pr_global_struct->other = EDICT_TO_PROG(sv.edicts); 609 PR_ExecuteProgram (ent->v.think); 610 if (ent->free) 611 return; 612VectorSubtract (ent->v.origin, oldorg, move); 613 614l = Length(move); 615if (l > 1.0/64) 616{ 617// Con_Printf ("**** snap: %f\n", Length (l)); 618 VectorCopy (oldorg, ent->v.origin); 619 SV_Push (ent, move); 620} 621 622 } 623 624} 625 626 627/* 628============= 629SV_Physics_None 630 631Non moving objects can only think 632============= 633*/ 634void SV_Physics_None (edict_t *ent) 635{ 636// regular thinking 637 SV_RunThink (ent); 638} 639 640/* 641============= 642SV_Physics_Noclip 643 644A moving object that doesn't obey physics 645============= 646*/ 647void SV_Physics_Noclip (edict_t *ent) 648{ 649// regular thinking 650 if (!SV_RunThink (ent)) 651 return; 652 653 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); 654 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); 655 656 SV_LinkEdict (ent, false); 657} 658 659/* 660============================================================================== 661 662TOSS / BOUNCE 663 664============================================================================== 665*/ 666 667/* 668============= 669SV_CheckWaterTransition 670 671============= 672*/ 673void SV_CheckWaterTransition (edict_t *ent) 674{ 675 int cont; 676 677 cont = SV_PointContents (ent->v.origin); 678 if (!ent->v.watertype) 679 { // just spawned here 680 ent->v.watertype = cont; 681 ent->v.waterlevel = 1; 682 return; 683 } 684 685 if (cont <= CONTENTS_WATER) 686 { 687 if (ent->v.watertype == CONTENTS_EMPTY) 688 { // just crossed into water 689 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); 690 } 691 ent->v.watertype = cont; 692 ent->v.waterlevel = 1; 693 } 694 else 695 { 696 if (ent->v.watertype != CONTENTS_EMPTY) 697 { // just crossed into water 698 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); 699 } 700 ent->v.watertype = CONTENTS_EMPTY; 701 ent->v.waterlevel = cont; 702 } 703} 704 705/* 706============= 707SV_Physics_Toss 708 709Toss, bounce, and fly movement. When onground, do nothing. 710============= 711*/ 712void SV_Physics_Toss (edict_t *ent) 713{ 714 trace_t trace; 715 vec3_t move; 716 float backoff; 717 718// regular thinking 719 if (!SV_RunThink (ent)) 720 return; 721 722 if (ent->v.velocity[2] > 0) 723 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; 724 725// if onground, return without moving 726 if ( ((int)ent->v.flags & FL_ONGROUND) ) 727 return; 728 729 SV_CheckVelocity (ent); 730 731// add gravity 732 if (ent->v.movetype != MOVETYPE_FLY 733 && ent->v.movetype != MOVETYPE_FLYMISSILE) 734 SV_AddGravity (ent, 1.0); 735 736// move angles 737 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); 738 739// move origin 740 VectorScale (ent->v.velocity, host_frametime, move); 741 trace = SV_PushEntity (ent, move); 742 if (trace.fraction == 1) 743 return; 744 if (ent->free) 745 return; 746 747 if (ent->v.movetype == MOVETYPE_BOUNCE) 748 backoff = 1.5; 749 else 750 backoff = 1; 751 752 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff); 753 754// stop if on ground 755 if (trace.plane.normal[2] > 0.7) 756 { 757 if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE ) 758 { 759 ent->v.flags = (int)ent->v.flags | FL_ONGROUND; 760 ent->v.groundentity = EDICT_TO_PROG(trace.ent); 761 VectorCopy (vec3_origin, ent->v.velocity); 762 VectorCopy (vec3_origin, ent->v.avelocity); 763 } 764 } 765 766// check for in water 767 SV_CheckWaterTransition (ent); 768} 769 770/* 771=============================================================================== 772 773STEPPING MOVEMENT 774 775=============================================================================== 776*/ 777 778/* 779============= 780SV_Physics_Step 781 782Monsters freefall when they don't have a ground entity, otherwise 783all movement is done with discrete steps. 784 785This is also used for objects that have become still on the ground, but 786will fall if the floor is pulled out from under them. 787FIXME: is this true? 788============= 789*/ 790void SV_Physics_Step (edict_t *ent) 791{ 792 qboolean hitsound; 793 794// frefall if not onground 795 if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) ) 796 { 797 if (ent->v.velocity[2] < movevars.gravity*-0.1) 798 hitsound = true; 799 else 800 hitsound = false; 801 802 SV_AddGravity (ent, 1.0); 803 SV_CheckVelocity (ent); 804 SV_FlyMove (ent, host_frametime, NULL); 805 SV_LinkEdict (ent, true); 806 807 if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground 808 { 809 if (hitsound) 810 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1); 811 } 812 } 813 814// regular thinking 815 SV_RunThink (ent); 816 817 SV_CheckWaterTransition (ent); 818} 819 820//============================================================================ 821 822void SV_ProgStartFrame (void) 823{ 824// let the progs know that a new frame has started 825 pr_global_struct->self = EDICT_TO_PROG(sv.edicts); 826 pr_global_struct->other = EDICT_TO_PROG(sv.edicts); 827 pr_global_struct->time = sv.time; 828 PR_ExecuteProgram (pr_global_struct->StartFrame); 829} 830 831/* 832================ 833SV_RunEntity 834 835================ 836*/ 837void SV_RunEntity (edict_t *ent) 838{ 839 if (ent->v.lastruntime == (float)realtime) 840 return; 841 ent->v.lastruntime = (float)realtime; 842 843 switch ( (int)ent->v.movetype) 844 { 845 case MOVETYPE_PUSH: 846 SV_Physics_Pusher (ent); 847 break; 848 case MOVETYPE_NONE: 849 SV_Physics_None (ent); 850 break; 851 case MOVETYPE_NOCLIP: 852 SV_Physics_Noclip (ent); 853 break; 854 case MOVETYPE_STEP: 855 SV_Physics_Step (ent); 856 break; 857 case MOVETYPE_TOSS: 858 case MOVETYPE_BOUNCE: 859 case MOVETYPE_FLY: 860 case MOVETYPE_FLYMISSILE: 861 SV_Physics_Toss (ent); 862 break; 863 default: 864 SV_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype); 865 } 866} 867 868/* 869================ 870SV_RunNewmis 871 872================ 873*/ 874void SV_RunNewmis (void) 875{ 876 edict_t *ent; 877 878 if (!pr_global_struct->newmis) 879 return; 880 ent = PROG_TO_EDICT(pr_global_struct->newmis); 881 host_frametime = 0.05; 882 pr_global_struct->newmis = 0; 883 884 SV_RunEntity (ent); 885} 886 887/* 888================ 889SV_Physics 890 891================ 892*/ 893void SV_Physics (void) 894{ 895 int i; 896 edict_t *ent; 897 static double old_time; 898 899// don't bother running a frame if sys_ticrate seconds haven't passed 900 host_frametime = realtime - old_time; 901 if (host_frametime < sv_mintic.value) 902 return; 903 if (host_frametime > sv_maxtic.value) 904 host_frametime = sv_maxtic.value; 905 old_time = realtime; 906 907 pr_global_struct->frametime = host_frametime; 908 909 SV_ProgStartFrame (); 910 911// 912// treat each object in turn 913// even the world gets a chance to think 914// 915 ent = sv.edicts; 916 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent)) 917 { 918 if (ent->free) 919 continue; 920 921 if (pr_global_struct->force_retouch) 922 SV_LinkEdict (ent, true); // force retouch even for stationary 923 924 if (i > 0 && i <= MAX_CLIENTS) 925 continue; // clients are run directly from packets 926 927 SV_RunEntity (ent); 928 SV_RunNewmis (); 929 } 930 931 if (pr_global_struct->force_retouch) 932 pr_global_struct->force_retouch--; 933} 934 935void SV_SetMoveVars(void) 936{ 937 movevars.gravity = sv_gravity.value; 938 movevars.stopspeed = sv_stopspeed.value; 939 movevars.maxspeed = sv_maxspeed.value; 940 movevars.spectatormaxspeed = sv_spectatormaxspeed.value; 941 movevars.accelerate = sv_accelerate.value; 942 movevars.airaccelerate = sv_airaccelerate.value; 943 movevars.wateraccelerate = sv_wateraccelerate.value; 944 movevars.friction = sv_friction.value; 945 movevars.waterfriction = sv_waterfriction.value; 946 movevars.entgravity = 1.0; 947} 948