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