|
|
1.1 ! root 1: // sv_phys.c ! 2: ! 3: #include "quakedef.h" ! 4: ! 5: /* ! 6: ! 7: ! 8: 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. ! 9: ! 10: onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects ! 11: ! 12: doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH ! 13: bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS ! 14: corpses are SOLID_NOT and MOVETYPE_TOSS ! 15: crates are SOLID_BBOX and MOVETYPE_TOSS ! 16: walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP ! 17: flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY ! 18: ! 19: solid_edge items only clip against bsp models. ! 20: ! 21: */ ! 22: ! 23: cvar_t sv_friction = {"sv_friction","4",false,true}; ! 24: cvar_t sv_stopspeed = {"sv_stopspeed","100"}; ! 25: cvar_t sv_gravity = {"sv_gravity","800",false,true}; ! 26: cvar_t sv_maxvelocity = {"sv_maxvelocity","2000"}; ! 27: cvar_t sv_nostep = {"sv_nostep","0"}; ! 28: ! 29: #define MOVE_EPSILON 0.01 ! 30: ! 31: void SV_Physics_Toss (edict_t *ent); ! 32: ! 33: /* ! 34: ================ ! 35: SV_CheckAllEnts ! 36: ================ ! 37: */ ! 38: void SV_CheckAllEnts (void) ! 39: { ! 40: int e; ! 41: edict_t *check; ! 42: ! 43: // see if any solid entities are inside the final position ! 44: check = NEXT_EDICT(sv.edicts); ! 45: for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) ! 46: { ! 47: if (check->free) ! 48: continue; ! 49: if (check->v.movetype == MOVETYPE_PUSH ! 50: || check->v.movetype == MOVETYPE_NONE ! 51: || check->v.movetype == MOVETYPE_NOCLIP) ! 52: continue; ! 53: ! 54: if (SV_TestEntityPosition (check)) ! 55: Con_Printf ("entity in invalid position\n"); ! 56: } ! 57: } ! 58: ! 59: /* ! 60: ================ ! 61: SV_CheckVelocity ! 62: ================ ! 63: */ ! 64: void SV_CheckVelocity (edict_t *ent) ! 65: { ! 66: int i; ! 67: ! 68: // ! 69: // bound velocity ! 70: // ! 71: for (i=0 ; i<3 ; i++) ! 72: { ! 73: if (IS_NAN(ent->v.velocity[i])) ! 74: { ! 75: Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname); ! 76: ent->v.velocity[i] = 0; ! 77: } ! 78: if (IS_NAN(ent->v.origin[i])) ! 79: { ! 80: Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname); ! 81: ent->v.origin[i] = 0; ! 82: } ! 83: if (ent->v.velocity[i] > sv_maxvelocity.value) ! 84: ent->v.velocity[i] = sv_maxvelocity.value; ! 85: else if (ent->v.velocity[i] < -sv_maxvelocity.value) ! 86: ent->v.velocity[i] = -sv_maxvelocity.value; ! 87: } ! 88: } ! 89: ! 90: /* ! 91: ============= ! 92: SV_RunThink ! 93: ! 94: Runs thinking code if time. There is some play in the exact time the think ! 95: function will be called, because it is called before any movement is done ! 96: in a frame. Not used for pushmove objects, because they must be exact. ! 97: Returns false if the entity removed itself. ! 98: ============= ! 99: */ ! 100: qboolean SV_RunThink (edict_t *ent) ! 101: { ! 102: float thinktime; ! 103: ! 104: thinktime = ent->v.nextthink; ! 105: if (thinktime <= 0 || thinktime > sv.time + host_frametime) ! 106: return true; ! 107: ! 108: if (thinktime < sv.time) ! 109: thinktime = sv.time; // don't let things stay in the past. ! 110: // it is possible to start that way ! 111: // by a trigger with a local time. ! 112: ent->v.nextthink = 0; ! 113: pr_global_struct->time = thinktime; ! 114: pr_global_struct->self = EDICT_TO_PROG(ent); ! 115: pr_global_struct->other = EDICT_TO_PROG(sv.edicts); ! 116: PR_ExecuteProgram (ent->v.think); ! 117: return !ent->free; ! 118: } ! 119: ! 120: /* ! 121: ================== ! 122: SV_Impact ! 123: ! 124: Two entities have touched, so run their touch functions ! 125: ================== ! 126: */ ! 127: void SV_Impact (edict_t *e1, edict_t *e2) ! 128: { ! 129: int old_self, old_other; ! 130: ! 131: old_self = pr_global_struct->self; ! 132: old_other = pr_global_struct->other; ! 133: ! 134: pr_global_struct->time = sv.time; ! 135: if (e1->v.touch && e1->v.solid != SOLID_NOT) ! 136: { ! 137: pr_global_struct->self = EDICT_TO_PROG(e1); ! 138: pr_global_struct->other = EDICT_TO_PROG(e2); ! 139: PR_ExecuteProgram (e1->v.touch); ! 140: } ! 141: ! 142: if (e2->v.touch && e2->v.solid != SOLID_NOT) ! 143: { ! 144: pr_global_struct->self = EDICT_TO_PROG(e2); ! 145: pr_global_struct->other = EDICT_TO_PROG(e1); ! 146: PR_ExecuteProgram (e2->v.touch); ! 147: } ! 148: ! 149: pr_global_struct->self = old_self; ! 150: pr_global_struct->other = old_other; ! 151: } ! 152: ! 153: ! 154: /* ! 155: ================== ! 156: ClipVelocity ! 157: ! 158: Slide off of the impacting object ! 159: returns the blocked flags (1 = floor, 2 = step / wall) ! 160: ================== ! 161: */ ! 162: #define STOP_EPSILON 0.1 ! 163: ! 164: int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) ! 165: { ! 166: float backoff; ! 167: float change; ! 168: int i, blocked; ! 169: ! 170: blocked = 0; ! 171: if (normal[2] > 0) ! 172: blocked |= 1; // floor ! 173: if (!normal[2]) ! 174: blocked |= 2; // step ! 175: ! 176: backoff = DotProduct (in, normal) * overbounce; ! 177: ! 178: for (i=0 ; i<3 ; i++) ! 179: { ! 180: change = normal[i]*backoff; ! 181: out[i] = in[i] - change; ! 182: if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) ! 183: out[i] = 0; ! 184: } ! 185: ! 186: return blocked; ! 187: } ! 188: ! 189: ! 190: /* ! 191: ============ ! 192: SV_FlyMove ! 193: ! 194: The basic solid body movement clip that slides along multiple planes ! 195: Returns the clipflags if the velocity was modified (hit something solid) ! 196: 1 = floor ! 197: 2 = wall / step ! 198: 4 = dead stop ! 199: If steptrace is not NULL, the trace of any vertical wall hit will be stored ! 200: ============ ! 201: */ ! 202: #define MAX_CLIP_PLANES 5 ! 203: int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) ! 204: { ! 205: int bumpcount, numbumps; ! 206: vec3_t dir; ! 207: float d; ! 208: int numplanes; ! 209: vec3_t planes[MAX_CLIP_PLANES]; ! 210: vec3_t primal_velocity, original_velocity, new_velocity; ! 211: int i, j; ! 212: trace_t trace; ! 213: vec3_t end; ! 214: float time_left; ! 215: int blocked; ! 216: ! 217: numbumps = 4; ! 218: ! 219: blocked = 0; ! 220: VectorCopy (ent->v.velocity, original_velocity); ! 221: VectorCopy (ent->v.velocity, primal_velocity); ! 222: numplanes = 0; ! 223: ! 224: time_left = time; ! 225: ! 226: for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) ! 227: { ! 228: for (i=0 ; i<3 ; i++) ! 229: end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i]; ! 230: ! 231: trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent); ! 232: ! 233: if (trace.allsolid) ! 234: { // entity is trapped in another solid ! 235: VectorCopy (vec3_origin, ent->v.velocity); ! 236: return 3; ! 237: } ! 238: ! 239: if (trace.fraction > 0) ! 240: { // actually covered some distance ! 241: VectorCopy (trace.endpos, ent->v.origin); ! 242: VectorCopy (ent->v.velocity, original_velocity); ! 243: numplanes = 0; ! 244: } ! 245: ! 246: if (trace.fraction == 1) ! 247: break; // moved the entire distance ! 248: ! 249: if (!trace.ent) ! 250: Sys_Error ("SV_FlyMove: !trace.ent"); ! 251: ! 252: if (trace.plane.normal[2] > 0.7) ! 253: { ! 254: blocked |= 1; // floor ! 255: if (trace.ent->v.solid == SOLID_BSP) ! 256: { ! 257: ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ! 258: ent->v.groundentity = EDICT_TO_PROG(trace.ent); ! 259: } ! 260: } ! 261: if (!trace.plane.normal[2]) ! 262: { ! 263: blocked |= 2; // step ! 264: if (steptrace) ! 265: *steptrace = trace; // save for player extrafriction ! 266: } ! 267: ! 268: // ! 269: // run the impact function ! 270: // ! 271: SV_Impact (ent, trace.ent); ! 272: if (ent->free) ! 273: break; // removed by the impact function ! 274: ! 275: ! 276: time_left -= time_left * trace.fraction; ! 277: ! 278: // cliped to another plane ! 279: if (numplanes >= MAX_CLIP_PLANES) ! 280: { // this shouldn't really happen ! 281: VectorCopy (vec3_origin, ent->v.velocity); ! 282: return 3; ! 283: } ! 284: ! 285: VectorCopy (trace.plane.normal, planes[numplanes]); ! 286: numplanes++; ! 287: ! 288: // ! 289: // modify original_velocity so it parallels all of the clip planes ! 290: // ! 291: for (i=0 ; i<numplanes ; i++) ! 292: { ! 293: ClipVelocity (original_velocity, planes[i], new_velocity, 1); ! 294: for (j=0 ; j<numplanes ; j++) ! 295: if (j != i) ! 296: { ! 297: if (DotProduct (new_velocity, planes[j]) < 0) ! 298: break; // not ok ! 299: } ! 300: if (j == numplanes) ! 301: break; ! 302: } ! 303: ! 304: if (i != numplanes) ! 305: { // go along this plane ! 306: VectorCopy (new_velocity, ent->v.velocity); ! 307: } ! 308: else ! 309: { // go along the crease ! 310: if (numplanes != 2) ! 311: { ! 312: // Con_Printf ("clip velocity, numplanes == %i\n",numplanes); ! 313: VectorCopy (vec3_origin, ent->v.velocity); ! 314: return 7; ! 315: } ! 316: CrossProduct (planes[0], planes[1], dir); ! 317: d = DotProduct (dir, ent->v.velocity); ! 318: VectorScale (dir, d, ent->v.velocity); ! 319: } ! 320: ! 321: // ! 322: // if original velocity is against the original velocity, stop dead ! 323: // to avoid tiny occilations in sloping corners ! 324: // ! 325: if (DotProduct (ent->v.velocity, primal_velocity) <= 0) ! 326: { ! 327: VectorCopy (vec3_origin, ent->v.velocity); ! 328: return blocked; ! 329: } ! 330: } ! 331: ! 332: return blocked; ! 333: } ! 334: ! 335: ! 336: /* ! 337: ============ ! 338: SV_AddGravity ! 339: ! 340: ============ ! 341: */ ! 342: void SV_AddGravity (edict_t *ent, float scale) ! 343: { ! 344: ent->v.velocity[2] -= scale * sv_gravity.value * host_frametime; ! 345: } ! 346: ! 347: /* ! 348: =============================================================================== ! 349: ! 350: PUSHMOVE ! 351: ! 352: =============================================================================== ! 353: */ ! 354: ! 355: /* ! 356: ============ ! 357: SV_PushEntity ! 358: ! 359: Does not change the entities velocity at all ! 360: ============ ! 361: */ ! 362: trace_t SV_PushEntity (edict_t *ent, vec3_t push) ! 363: { ! 364: trace_t trace; ! 365: vec3_t end; ! 366: ! 367: VectorAdd (ent->v.origin, push, end); ! 368: ! 369: if (ent->v.movetype == MOVETYPE_FLYMISSILE) ! 370: trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent); ! 371: else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT) ! 372: // only clip against bmodels ! 373: trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent); ! 374: else ! 375: trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); ! 376: ! 377: VectorCopy (trace.endpos, ent->v.origin); ! 378: SV_LinkEdict (ent, true); ! 379: ! 380: if (trace.ent) ! 381: SV_Impact (ent, trace.ent); ! 382: ! 383: return trace; ! 384: } ! 385: ! 386: ! 387: /* ! 388: ============ ! 389: SV_PushMove ! 390: ! 391: ============ ! 392: */ ! 393: void SV_PushMove (edict_t *pusher, float movetime) ! 394: { ! 395: int i, e; ! 396: edict_t *check, *block; ! 397: vec3_t mins, maxs, move; ! 398: vec3_t entorig, pushorig; ! 399: int num_moved; ! 400: edict_t *moved_edict[MAX_EDICTS]; ! 401: vec3_t moved_from[MAX_EDICTS]; ! 402: ! 403: if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) ! 404: { ! 405: pusher->v.ltime += movetime; ! 406: return; ! 407: } ! 408: ! 409: for (i=0 ; i<3 ; i++) ! 410: { ! 411: move[i] = pusher->v.velocity[i] * movetime; ! 412: mins[i] = pusher->v.absmin[i] + move[i]; ! 413: maxs[i] = pusher->v.absmax[i] + move[i]; ! 414: } ! 415: ! 416: VectorCopy (pusher->v.origin, pushorig); ! 417: ! 418: // move the pusher to it's final position ! 419: ! 420: VectorAdd (pusher->v.origin, move, pusher->v.origin); ! 421: pusher->v.ltime += movetime; ! 422: SV_LinkEdict (pusher, false); ! 423: ! 424: ! 425: // see if any solid entities are inside the final position ! 426: num_moved = 0; ! 427: check = NEXT_EDICT(sv.edicts); ! 428: for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) ! 429: { ! 430: if (check->free) ! 431: continue; ! 432: if (check->v.movetype == MOVETYPE_PUSH ! 433: || check->v.movetype == MOVETYPE_NONE ! 434: || check->v.movetype == MOVETYPE_NOCLIP) ! 435: continue; ! 436: ! 437: // if the entity is standing on the pusher, it will definately be moved ! 438: if ( ! ( ((int)check->v.flags & FL_ONGROUND) ! 439: && PROG_TO_EDICT(check->v.groundentity) == pusher) ) ! 440: { ! 441: if ( check->v.absmin[0] >= maxs[0] ! 442: || check->v.absmin[1] >= maxs[1] ! 443: || check->v.absmin[2] >= maxs[2] ! 444: || check->v.absmax[0] <= mins[0] ! 445: || check->v.absmax[1] <= mins[1] ! 446: || check->v.absmax[2] <= mins[2] ) ! 447: continue; ! 448: ! 449: // see if the ent's bbox is inside the pusher's final position ! 450: if (!SV_TestEntityPosition (check)) ! 451: continue; ! 452: } ! 453: ! 454: // remove the onground flag for non-players ! 455: if (check->v.movetype != MOVETYPE_WALK) ! 456: check->v.flags = (int)check->v.flags & ~FL_ONGROUND; ! 457: ! 458: VectorCopy (check->v.origin, entorig); ! 459: VectorCopy (check->v.origin, moved_from[num_moved]); ! 460: moved_edict[num_moved] = check; ! 461: num_moved++; ! 462: ! 463: // try moving the contacted entity ! 464: pusher->v.solid = SOLID_NOT; ! 465: SV_PushEntity (check, move); ! 466: pusher->v.solid = SOLID_BSP; ! 467: ! 468: // if it is still inside the pusher, block ! 469: block = SV_TestEntityPosition (check); ! 470: if (block) ! 471: { // fail the move ! 472: if (check->v.mins[0] == check->v.maxs[0]) ! 473: continue; ! 474: if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) ! 475: { // corpse ! 476: check->v.mins[0] = check->v.mins[1] = 0; ! 477: VectorCopy (check->v.mins, check->v.maxs); ! 478: continue; ! 479: } ! 480: ! 481: VectorCopy (entorig, check->v.origin); ! 482: SV_LinkEdict (check, true); ! 483: ! 484: VectorCopy (pushorig, pusher->v.origin); ! 485: SV_LinkEdict (pusher, false); ! 486: pusher->v.ltime -= movetime; ! 487: ! 488: // if the pusher has a "blocked" function, call it ! 489: // otherwise, just stay in place until the obstacle is gone ! 490: if (pusher->v.blocked) ! 491: { ! 492: pr_global_struct->self = EDICT_TO_PROG(pusher); ! 493: pr_global_struct->other = EDICT_TO_PROG(check); ! 494: PR_ExecuteProgram (pusher->v.blocked); ! 495: } ! 496: ! 497: // move back any entities we already moved ! 498: for (i=0 ; i<num_moved ; i++) ! 499: { ! 500: VectorCopy (moved_from[i], moved_edict[i]->v.origin); ! 501: SV_LinkEdict (moved_edict[i], false); ! 502: } ! 503: return; ! 504: } ! 505: } ! 506: ! 507: ! 508: } ! 509: ! 510: ! 511: /* ! 512: ================ ! 513: SV_Physics_Pusher ! 514: ! 515: ================ ! 516: */ ! 517: void SV_Physics_Pusher (edict_t *ent) ! 518: { ! 519: float thinktime; ! 520: float oldltime; ! 521: float movetime; ! 522: ! 523: oldltime = ent->v.ltime; ! 524: ! 525: thinktime = ent->v.nextthink; ! 526: if (thinktime < ent->v.ltime + host_frametime) ! 527: { ! 528: movetime = thinktime - ent->v.ltime; ! 529: if (movetime < 0) ! 530: movetime = 0; ! 531: } ! 532: else ! 533: movetime = host_frametime; ! 534: ! 535: if (movetime) ! 536: { ! 537: SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked ! 538: } ! 539: ! 540: if (thinktime > oldltime && thinktime <= ent->v.ltime) ! 541: { ! 542: ent->v.nextthink = 0; ! 543: pr_global_struct->time = sv.time; ! 544: pr_global_struct->self = EDICT_TO_PROG(ent); ! 545: pr_global_struct->other = EDICT_TO_PROG(sv.edicts); ! 546: PR_ExecuteProgram (ent->v.think); ! 547: if (ent->free) ! 548: return; ! 549: } ! 550: ! 551: } ! 552: ! 553: ! 554: /* ! 555: =============================================================================== ! 556: ! 557: CLIENT MOVEMENT ! 558: ! 559: =============================================================================== ! 560: */ ! 561: ! 562: /* ! 563: ============= ! 564: SV_CheckStuck ! 565: ! 566: This is a big hack to try and fix the rare case of getting stuck in the world ! 567: clipping hull. ! 568: ============= ! 569: */ ! 570: void SV_CheckStuck (edict_t *ent) ! 571: { ! 572: int i, j; ! 573: int z; ! 574: vec3_t org; ! 575: ! 576: if (!SV_TestEntityPosition(ent)) ! 577: { ! 578: VectorCopy (ent->v.origin, ent->v.oldorigin); ! 579: return; ! 580: } ! 581: ! 582: VectorCopy (ent->v.origin, org); ! 583: VectorCopy (ent->v.oldorigin, ent->v.origin); ! 584: if (!SV_TestEntityPosition(ent)) ! 585: { ! 586: Con_Printf ("Unstuck.\n"); ! 587: SV_LinkEdict (ent, true); ! 588: return; ! 589: } ! 590: ! 591: for (z=0 ; z< 18 ; z++) ! 592: for (i=-1 ; i <= 1 ; i++) ! 593: for (j=-1 ; j <= 1 ; j++) ! 594: { ! 595: ent->v.origin[0] = org[0] + i; ! 596: ent->v.origin[1] = org[1] + j; ! 597: ent->v.origin[2] = org[2] + z; ! 598: if (!SV_TestEntityPosition(ent)) ! 599: { ! 600: Con_DPrintf ("Unstuck.\n"); ! 601: SV_LinkEdict (ent, true); ! 602: return; ! 603: } ! 604: } ! 605: ! 606: VectorCopy (org, ent->v.origin); ! 607: Con_DPrintf ("player is stuck.\n"); ! 608: } ! 609: ! 610: ! 611: /* ! 612: ============= ! 613: SV_CheckWater ! 614: ============= ! 615: */ ! 616: qboolean SV_CheckWater (edict_t *ent) ! 617: { ! 618: vec3_t point; ! 619: int cont; ! 620: ! 621: point[0] = ent->v.origin[0]; ! 622: point[1] = ent->v.origin[1]; ! 623: ! 624: ent->v.waterlevel = 0; ! 625: ent->v.watertype = CONTENTS_EMPTY; ! 626: point[2] = ent->v.origin[2] + ent->v.mins[2] + 1; ! 627: cont = SV_PointContents (point); ! 628: if (cont <= CONTENTS_WATER) ! 629: { ! 630: ent->v.watertype = cont; ! 631: ent->v.waterlevel = 1; ! 632: point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5; ! 633: cont = SV_PointContents (point); ! 634: if (cont <= CONTENTS_WATER) ! 635: { ! 636: ent->v.waterlevel = 2; ! 637: point[2] = ent->v.origin[2] + ent->v.view_ofs[2]; ! 638: cont = SV_PointContents (point); ! 639: if (cont <= CONTENTS_WATER) ! 640: ent->v.waterlevel = 3; ! 641: } ! 642: } ! 643: ! 644: return ent->v.waterlevel > 1; ! 645: } ! 646: ! 647: /* ! 648: ============ ! 649: SV_WallFriction ! 650: ! 651: ============ ! 652: */ ! 653: void SV_WallFriction (edict_t *ent, trace_t *trace) ! 654: { ! 655: vec3_t forward, right, up; ! 656: float d, i; ! 657: vec3_t into, side; ! 658: ! 659: AngleVectors (ent->v.v_angle, forward, right, up); ! 660: d = DotProduct (trace->plane.normal, forward); ! 661: ! 662: d += 0.5; ! 663: if (d >= 0) ! 664: return; ! 665: ! 666: // cut the tangential velocity ! 667: i = DotProduct (trace->plane.normal, ent->v.velocity); ! 668: VectorScale (trace->plane.normal, i, into); ! 669: VectorSubtract (ent->v.velocity, into, side); ! 670: ! 671: ent->v.velocity[0] = side[0] * (1 + d); ! 672: ent->v.velocity[1] = side[1] * (1 + d); ! 673: } ! 674: ! 675: /* ! 676: ===================== ! 677: SV_TryUnstick ! 678: ! 679: Player has come to a dead stop, possibly due to the problem with limited ! 680: float precision at some angle joins in the BSP hull. ! 681: ! 682: Try fixing by pushing one pixel in each direction. ! 683: ! 684: This is a hack, but in the interest of good gameplay... ! 685: ====================== ! 686: */ ! 687: int SV_TryUnstick (edict_t *ent, vec3_t oldvel) ! 688: { ! 689: int i; ! 690: vec3_t oldorg; ! 691: vec3_t dir; ! 692: int clip; ! 693: trace_t steptrace; ! 694: ! 695: VectorCopy (ent->v.origin, oldorg); ! 696: VectorCopy (vec3_origin, dir); ! 697: ! 698: for (i=0 ; i<8 ; i++) ! 699: { ! 700: // try pushing a little in an axial direction ! 701: switch (i) ! 702: { ! 703: case 0: dir[0] = 2; dir[1] = 0; break; ! 704: case 1: dir[0] = 0; dir[1] = 2; break; ! 705: case 2: dir[0] = -2; dir[1] = 0; break; ! 706: case 3: dir[0] = 0; dir[1] = -2; break; ! 707: case 4: dir[0] = 2; dir[1] = 2; break; ! 708: case 5: dir[0] = -2; dir[1] = 2; break; ! 709: case 6: dir[0] = 2; dir[1] = -2; break; ! 710: case 7: dir[0] = -2; dir[1] = -2; break; ! 711: } ! 712: ! 713: SV_PushEntity (ent, dir); ! 714: ! 715: // retry the original move ! 716: ent->v.velocity[0] = oldvel[0]; ! 717: ent->v. velocity[1] = oldvel[1]; ! 718: ent->v. velocity[2] = 0; ! 719: clip = SV_FlyMove (ent, 0.1, &steptrace); ! 720: ! 721: if ( fabs(oldorg[1] - ent->v.origin[1]) > 4 ! 722: || fabs(oldorg[0] - ent->v.origin[0]) > 4 ) ! 723: { ! 724: //Con_Printf ("unstuck!\n"); ! 725: return clip; ! 726: } ! 727: ! 728: // go back to the original pos and try again ! 729: VectorCopy (oldorg, ent->v.origin); ! 730: } ! 731: ! 732: VectorCopy (vec3_origin, ent->v.velocity); ! 733: return 7; // still not moving ! 734: } ! 735: ! 736: /* ! 737: ===================== ! 738: SV_WalkMove ! 739: ! 740: Only used by players ! 741: ====================== ! 742: */ ! 743: #define STEPSIZE 18 ! 744: void SV_WalkMove (edict_t *ent) ! 745: { ! 746: vec3_t upmove, downmove; ! 747: vec3_t oldorg, oldvel; ! 748: vec3_t nosteporg, nostepvel; ! 749: int clip; ! 750: int oldonground; ! 751: trace_t steptrace, downtrace; ! 752: ! 753: // ! 754: // do a regular slide move unless it looks like you ran into a step ! 755: // ! 756: oldonground = (int)ent->v.flags & FL_ONGROUND; ! 757: ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; ! 758: ! 759: VectorCopy (ent->v.origin, oldorg); ! 760: VectorCopy (ent->v.velocity, oldvel); ! 761: ! 762: clip = SV_FlyMove (ent, host_frametime, &steptrace); ! 763: ! 764: if ( !(clip & 2) ) ! 765: return; // move didn't block on a step ! 766: ! 767: if (!oldonground && ent->v.waterlevel == 0) ! 768: return; // don't stair up while jumping ! 769: ! 770: if (ent->v.movetype != MOVETYPE_WALK) ! 771: return; // gibbed by a trigger ! 772: ! 773: if (sv_nostep.value) ! 774: return; ! 775: ! 776: if ( (int)sv_player->v.flags & FL_WATERJUMP ) ! 777: return; ! 778: ! 779: VectorCopy (ent->v.origin, nosteporg); ! 780: VectorCopy (ent->v.velocity, nostepvel); ! 781: ! 782: // ! 783: // try moving up and forward to go up a step ! 784: // ! 785: VectorCopy (oldorg, ent->v.origin); // back to start pos ! 786: ! 787: VectorCopy (vec3_origin, upmove); ! 788: VectorCopy (vec3_origin, downmove); ! 789: upmove[2] = STEPSIZE; ! 790: downmove[2] = -STEPSIZE + oldvel[2]*host_frametime; ! 791: ! 792: // move up ! 793: SV_PushEntity (ent, upmove); // FIXME: don't link? ! 794: ! 795: // move forward ! 796: ent->v.velocity[0] = oldvel[0]; ! 797: ent->v. velocity[1] = oldvel[1]; ! 798: ent->v. velocity[2] = 0; ! 799: clip = SV_FlyMove (ent, host_frametime, &steptrace); ! 800: ! 801: // check for stuckness, possibly due to the limited precision of floats ! 802: // in the clipping hulls ! 803: if (clip) ! 804: { ! 805: if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125 ! 806: && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 ) ! 807: { // stepping up didn't make any progress ! 808: clip = SV_TryUnstick (ent, oldvel); ! 809: } ! 810: } ! 811: ! 812: // extra friction based on view angle ! 813: if ( clip & 2 ) ! 814: SV_WallFriction (ent, &steptrace); ! 815: ! 816: // move down ! 817: downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link? ! 818: ! 819: if (downtrace.plane.normal[2] > 0.7) ! 820: { ! 821: if (ent->v.solid == SOLID_BSP) ! 822: { ! 823: ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ! 824: ent->v.groundentity = EDICT_TO_PROG(downtrace.ent); ! 825: } ! 826: } ! 827: else ! 828: { ! 829: // if the push down didn't end up on good ground, use the move without ! 830: // the step up. This happens near wall / slope combinations, and can ! 831: // cause the player to hop up higher on a slope too steep to climb ! 832: VectorCopy (nosteporg, ent->v.origin); ! 833: VectorCopy (nostepvel, ent->v.velocity); ! 834: } ! 835: } ! 836: ! 837: ! 838: /* ! 839: ================ ! 840: SV_Physics_Client ! 841: ! 842: Player character actions ! 843: ================ ! 844: */ ! 845: void SV_Physics_Client (edict_t *ent, int num) ! 846: { ! 847: if ( ! svs.clients[num-1].active ) ! 848: return; // unconnected slot ! 849: ! 850: // ! 851: // call standard client pre-think ! 852: // ! 853: pr_global_struct->time = sv.time; ! 854: pr_global_struct->self = EDICT_TO_PROG(ent); ! 855: PR_ExecuteProgram (pr_global_struct->PlayerPreThink); ! 856: ! 857: // ! 858: // do a move ! 859: // ! 860: SV_CheckVelocity (ent); ! 861: ! 862: // ! 863: // decide which move function to call ! 864: // ! 865: switch ((int)ent->v.movetype) ! 866: { ! 867: case MOVETYPE_NONE: ! 868: if (!SV_RunThink (ent)) ! 869: return; ! 870: break; ! 871: ! 872: case MOVETYPE_WALK: ! 873: if (!SV_RunThink (ent)) ! 874: return; ! 875: if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) ) ! 876: SV_AddGravity (ent, 1.0); ! 877: SV_CheckStuck (ent); ! 878: SV_WalkMove (ent); ! 879: break; ! 880: ! 881: case MOVETYPE_TOSS: ! 882: case MOVETYPE_BOUNCE: ! 883: SV_Physics_Toss (ent); ! 884: break; ! 885: ! 886: case MOVETYPE_FLY: ! 887: if (!SV_RunThink (ent)) ! 888: return; ! 889: SV_FlyMove (ent, host_frametime, NULL); ! 890: break; ! 891: ! 892: case MOVETYPE_NOCLIP: ! 893: if (!SV_RunThink (ent)) ! 894: return; ! 895: VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); ! 896: break; ! 897: ! 898: default: ! 899: Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype); ! 900: } ! 901: ! 902: // ! 903: // call standard player post-think ! 904: // ! 905: SV_LinkEdict (ent, true); ! 906: ! 907: pr_global_struct->time = sv.time; ! 908: pr_global_struct->self = EDICT_TO_PROG(ent); ! 909: PR_ExecuteProgram (pr_global_struct->PlayerPostThink); ! 910: } ! 911: ! 912: //============================================================================ ! 913: ! 914: /* ! 915: ============= ! 916: SV_Physics_None ! 917: ! 918: Non moving objects can only think ! 919: ============= ! 920: */ ! 921: void SV_Physics_None (edict_t *ent) ! 922: { ! 923: // regular thinking ! 924: SV_RunThink (ent); ! 925: } ! 926: ! 927: /* ! 928: ============= ! 929: SV_Physics_Noclip ! 930: ! 931: A moving object that doesn't obey physics ! 932: ============= ! 933: */ ! 934: void SV_Physics_Noclip (edict_t *ent) ! 935: { ! 936: // regular thinking ! 937: if (!SV_RunThink (ent)) ! 938: return; ! 939: ! 940: VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); ! 941: VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); ! 942: ! 943: SV_LinkEdict (ent, false); ! 944: } ! 945: ! 946: /* ! 947: ============================================================================== ! 948: ! 949: TOSS / BOUNCE ! 950: ! 951: ============================================================================== ! 952: */ ! 953: ! 954: /* ! 955: ============= ! 956: SV_CheckWaterTransition ! 957: ! 958: ============= ! 959: */ ! 960: void SV_CheckWaterTransition (edict_t *ent) ! 961: { ! 962: int cont; ! 963: ! 964: cont = SV_PointContents (ent->v.origin); ! 965: if (!ent->v.watertype) ! 966: { // just spawned here ! 967: ent->v.watertype = cont; ! 968: ent->v.waterlevel = 1; ! 969: return; ! 970: } ! 971: ! 972: if (cont <= CONTENTS_WATER) ! 973: { ! 974: if (ent->v.watertype == CONTENTS_EMPTY) ! 975: { // just crossed into water ! 976: SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); ! 977: } ! 978: ent->v.watertype = cont; ! 979: ent->v.waterlevel = 1; ! 980: } ! 981: else ! 982: { ! 983: if (ent->v.watertype != CONTENTS_EMPTY) ! 984: { // just crossed into water ! 985: SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); ! 986: } ! 987: ent->v.watertype = CONTENTS_EMPTY; ! 988: ent->v.waterlevel = cont; ! 989: } ! 990: } ! 991: ! 992: /* ! 993: ============= ! 994: SV_Physics_Toss ! 995: ! 996: Toss, bounce, and fly movement. When onground, do nothing. ! 997: ============= ! 998: */ ! 999: void SV_Physics_Toss (edict_t *ent) ! 1000: { ! 1001: trace_t trace; ! 1002: vec3_t move; ! 1003: float backoff; ! 1004: ! 1005: // regular thinking ! 1006: if (!SV_RunThink (ent)) ! 1007: return; ! 1008: ! 1009: // if onground, return without moving ! 1010: if ( ((int)ent->v.flags & FL_ONGROUND) ) ! 1011: return; ! 1012: ! 1013: SV_CheckVelocity (ent); ! 1014: ! 1015: // add gravity ! 1016: if (ent->v.movetype != MOVETYPE_FLY ! 1017: && ent->v.movetype != MOVETYPE_FLYMISSILE) ! 1018: SV_AddGravity (ent, 1.0); ! 1019: ! 1020: // move angles ! 1021: VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); ! 1022: ! 1023: // move origin ! 1024: VectorScale (ent->v.velocity, host_frametime, move); ! 1025: trace = SV_PushEntity (ent, move); ! 1026: if (trace.fraction == 1) ! 1027: return; ! 1028: if (ent->free) ! 1029: return; ! 1030: ! 1031: if (ent->v.movetype == MOVETYPE_BOUNCE) ! 1032: backoff = 1.5; ! 1033: else ! 1034: backoff = 1; ! 1035: ! 1036: ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff); ! 1037: ! 1038: // stop if on ground ! 1039: if (trace.plane.normal[2] > 0.7) ! 1040: { ! 1041: if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE ) ! 1042: { ! 1043: ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ! 1044: ent->v.groundentity = EDICT_TO_PROG(trace.ent); ! 1045: VectorCopy (vec3_origin, ent->v.velocity); ! 1046: VectorCopy (vec3_origin, ent->v.avelocity); ! 1047: } ! 1048: } ! 1049: ! 1050: // check for in water ! 1051: SV_CheckWaterTransition (ent); ! 1052: } ! 1053: ! 1054: /* ! 1055: =============================================================================== ! 1056: ! 1057: STEPPING MOVEMENT ! 1058: ! 1059: =============================================================================== ! 1060: */ ! 1061: ! 1062: /* ! 1063: ============= ! 1064: SV_Physics_Step ! 1065: ! 1066: Monsters freefall when they don't have a ground entity, otherwise ! 1067: all movement is done with discrete steps. ! 1068: ! 1069: This is also used for objects that have become still on the ground, but ! 1070: will fall if the floor is pulled out from under them. ! 1071: ============= ! 1072: */ ! 1073: void SV_Physics_Step (edict_t *ent) ! 1074: { ! 1075: qboolean hitsound; ! 1076: ! 1077: // frefall if not onground ! 1078: if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) ) ! 1079: { ! 1080: if (ent->v.velocity[2] < sv_gravity.value*-0.1) ! 1081: hitsound = true; ! 1082: else ! 1083: hitsound = false; ! 1084: ! 1085: SV_AddGravity (ent, 1.0); ! 1086: SV_CheckVelocity (ent); ! 1087: SV_FlyMove (ent, host_frametime, NULL); ! 1088: SV_LinkEdict (ent, true); ! 1089: ! 1090: if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground ! 1091: { ! 1092: if (hitsound) ! 1093: SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1); ! 1094: } ! 1095: } ! 1096: ! 1097: // regular thinking ! 1098: SV_RunThink (ent); ! 1099: ! 1100: SV_CheckWaterTransition (ent); ! 1101: } ! 1102: ! 1103: //============================================================================ ! 1104: ! 1105: /* ! 1106: ================ ! 1107: SV_Physics ! 1108: ! 1109: ================ ! 1110: */ ! 1111: void SV_Physics (void) ! 1112: { ! 1113: int i; ! 1114: edict_t *ent; ! 1115: ! 1116: // let the progs know that a new frame has started ! 1117: pr_global_struct->self = EDICT_TO_PROG(sv.edicts); ! 1118: pr_global_struct->other = EDICT_TO_PROG(sv.edicts); ! 1119: pr_global_struct->time = sv.time; ! 1120: PR_ExecuteProgram (pr_global_struct->StartFrame); ! 1121: ! 1122: //SV_CheckAllEnts (); ! 1123: ! 1124: // ! 1125: // treat each object in turn ! 1126: // ! 1127: ent = sv.edicts; ! 1128: for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent)) ! 1129: { ! 1130: if (ent->free) ! 1131: continue; ! 1132: ! 1133: if (pr_global_struct->force_retouch) ! 1134: { ! 1135: SV_LinkEdict (ent, true); // force retouch even for stationary ! 1136: } ! 1137: ! 1138: if (i > 0 && i <= svs.maxclients) ! 1139: SV_Physics_Client (ent, i); ! 1140: else if (ent->v.movetype == MOVETYPE_PUSH) ! 1141: SV_Physics_Pusher (ent); ! 1142: else if (ent->v.movetype == MOVETYPE_NONE) ! 1143: SV_Physics_None (ent); ! 1144: else if (ent->v.movetype == MOVETYPE_NOCLIP) ! 1145: SV_Physics_Noclip (ent); ! 1146: else if (ent->v.movetype == MOVETYPE_STEP) ! 1147: SV_Physics_Step (ent); ! 1148: else if (ent->v.movetype == MOVETYPE_TOSS ! 1149: || ent->v.movetype == MOVETYPE_BOUNCE ! 1150: || ent->v.movetype == MOVETYPE_FLY ! 1151: || ent->v.movetype == MOVETYPE_FLYMISSILE) ! 1152: SV_Physics_Toss (ent); ! 1153: else ! 1154: Sys_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype); ! 1155: } ! 1156: ! 1157: if (pr_global_struct->force_retouch) ! 1158: pr_global_struct->force_retouch--; ! 1159: ! 1160: sv.time += host_frametime; ! 1161: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.