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