|
|
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: ! 255: for (j=0 ; j<numplanes ; j++) ! 256: if ((j != i) && !VectorCompare (planes[i], planes[j])) ! 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: // RAFAEL ! 688: // move type for rippergun projectile ! 689: && ent->movetype != MOVETYPE_WALLBOUNCE) ! 690: SV_AddGravity (ent); ! 691: ! 692: // move angles ! 693: VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); ! 694: ! 695: // move origin ! 696: VectorScale (ent->velocity, FRAMETIME, move); ! 697: trace = SV_PushEntity (ent, move); ! 698: if (!ent->inuse) ! 699: return; ! 700: ! 701: if (trace.fraction < 1) ! 702: { ! 703: // RAFAEL ! 704: if (ent->movetype == MOVETYPE_WALLBOUNCE) ! 705: backoff = 2.0; ! 706: // RAFAEL ( else ) ! 707: else if (ent->movetype == MOVETYPE_BOUNCE) ! 708: backoff = 1.5; ! 709: else ! 710: backoff = 1; ! 711: ! 712: ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff); ! 713: ! 714: // RAFAEL ! 715: if (ent->movetype == MOVETYPE_WALLBOUNCE) ! 716: vectoangles (ent->velocity, ent->s.angles); ! 717: ! 718: // stop if on ground ! 719: // RAFAEL ! 720: if (trace.plane.normal[2] > 0.7 && ent->movetype != MOVETYPE_WALLBOUNCE) ! 721: { ! 722: if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE ) ! 723: { ! 724: ent->groundentity = trace.ent; ! 725: ent->groundentity_linkcount = trace.ent->linkcount; ! 726: VectorCopy (vec3_origin, ent->velocity); ! 727: VectorCopy (vec3_origin, ent->avelocity); ! 728: } ! 729: } ! 730: ! 731: // if (ent->touch) ! 732: // ent->touch (ent, trace.ent, &trace.plane, trace.surface); ! 733: } ! 734: ! 735: // check for water transition ! 736: wasinwater = (ent->watertype & MASK_WATER); ! 737: ent->watertype = gi.pointcontents (ent->s.origin); ! 738: isinwater = ent->watertype & MASK_WATER; ! 739: ! 740: if (isinwater) ! 741: ent->waterlevel = 1; ! 742: else ! 743: ent->waterlevel = 0; ! 744: ! 745: if (!wasinwater && isinwater) ! 746: gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); ! 747: else if (wasinwater && !isinwater) ! 748: gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); ! 749: ! 750: // move teamslaves ! 751: for (slave = ent->teamchain; slave; slave = slave->teamchain) ! 752: { ! 753: VectorCopy (ent->s.origin, slave->s.origin); ! 754: gi.linkentity (slave); ! 755: } ! 756: } ! 757: ! 758: /* ! 759: =============================================================================== ! 760: ! 761: STEPPING MOVEMENT ! 762: ! 763: =============================================================================== ! 764: */ ! 765: ! 766: /* ! 767: ============= ! 768: SV_Physics_Step ! 769: ! 770: Monsters freefall when they don't have a ground entity, otherwise ! 771: all movement is done with discrete steps. ! 772: ! 773: This is also used for objects that have become still on the ground, but ! 774: will fall if the floor is pulled out from under them. ! 775: FIXME: is this true? ! 776: ============= ! 777: */ ! 778: ! 779: //FIXME: hacked in for E3 demo ! 780: #define sv_stopspeed 100 ! 781: #define sv_friction 6 ! 782: #define sv_waterfriction 1 ! 783: ! 784: void SV_AddRotationalFriction (edict_t *ent) ! 785: { ! 786: int n; ! 787: float adjustment; ! 788: ! 789: VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); ! 790: adjustment = FRAMETIME * sv_stopspeed * sv_friction; ! 791: for (n = 0; n < 3; n++) ! 792: { ! 793: if (ent->avelocity[n] > 0) ! 794: { ! 795: ent->avelocity[n] -= adjustment; ! 796: if (ent->avelocity[n] < 0) ! 797: ent->avelocity[n] = 0; ! 798: } ! 799: else ! 800: { ! 801: ent->avelocity[n] += adjustment; ! 802: if (ent->avelocity[n] > 0) ! 803: ent->avelocity[n] = 0; ! 804: } ! 805: } ! 806: } ! 807: ! 808: void SV_Physics_Step (edict_t *ent) ! 809: { ! 810: qboolean wasonground; ! 811: qboolean hitsound = false; ! 812: float *vel; ! 813: float speed, newspeed, control; ! 814: float friction; ! 815: edict_t *groundentity; ! 816: int mask; ! 817: ! 818: // airborn monsters should always check for ground ! 819: if (!ent->groundentity) ! 820: M_CheckGround (ent); ! 821: ! 822: groundentity = ent->groundentity; ! 823: ! 824: SV_CheckVelocity (ent); ! 825: ! 826: if (groundentity) ! 827: wasonground = true; ! 828: else ! 829: wasonground = false; ! 830: ! 831: if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) ! 832: SV_AddRotationalFriction (ent); ! 833: ! 834: // add gravity except: ! 835: // flying monsters ! 836: // swimming monsters who are in the water ! 837: if (! wasonground) ! 838: if (!(ent->flags & FL_FLY)) ! 839: if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) ! 840: { ! 841: if (ent->velocity[2] < sv_gravity->value*-0.1) ! 842: hitsound = true; ! 843: if (ent->waterlevel == 0) ! 844: SV_AddGravity (ent); ! 845: } ! 846: ! 847: // friction for flying monsters that have been given vertical velocity ! 848: if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) ! 849: { ! 850: speed = fabs(ent->velocity[2]); ! 851: control = speed < sv_stopspeed ? sv_stopspeed : speed; ! 852: friction = sv_friction/3; ! 853: newspeed = speed - (FRAMETIME * control * friction); ! 854: if (newspeed < 0) ! 855: newspeed = 0; ! 856: newspeed /= speed; ! 857: ent->velocity[2] *= newspeed; ! 858: } ! 859: ! 860: // friction for flying monsters that have been given vertical velocity ! 861: if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) ! 862: { ! 863: speed = fabs(ent->velocity[2]); ! 864: control = speed < sv_stopspeed ? sv_stopspeed : speed; ! 865: newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel); ! 866: if (newspeed < 0) ! 867: newspeed = 0; ! 868: newspeed /= speed; ! 869: ent->velocity[2] *= newspeed; ! 870: } ! 871: ! 872: if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) ! 873: { ! 874: // apply friction ! 875: // let dead monsters who aren't completely onground slide ! 876: if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY))) ! 877: if (!(ent->health <= 0.0 && !M_CheckBottom(ent))) ! 878: { ! 879: vel = ent->velocity; ! 880: speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); ! 881: if (speed) ! 882: { ! 883: friction = sv_friction; ! 884: ! 885: control = speed < sv_stopspeed ? sv_stopspeed : speed; ! 886: newspeed = speed - FRAMETIME*control*friction; ! 887: ! 888: if (newspeed < 0) ! 889: newspeed = 0; ! 890: newspeed /= speed; ! 891: ! 892: vel[0] *= newspeed; ! 893: vel[1] *= newspeed; ! 894: } ! 895: } ! 896: ! 897: if (ent->svflags & SVF_MONSTER) ! 898: mask = MASK_MONSTERSOLID; ! 899: else ! 900: mask = MASK_SOLID; ! 901: SV_FlyMove (ent, FRAMETIME, mask); ! 902: ! 903: gi.linkentity (ent); ! 904: G_TouchTriggers (ent); ! 905: if (!ent->inuse) ! 906: return; ! 907: ! 908: if (ent->groundentity) ! 909: if (!wasonground) ! 910: if (hitsound) ! 911: gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0); ! 912: } ! 913: ! 914: // regular thinking ! 915: SV_RunThink (ent); ! 916: } ! 917: ! 918: //============================================================================ ! 919: /* ! 920: ================ ! 921: G_RunEntity ! 922: ! 923: ================ ! 924: */ ! 925: void G_RunEntity (edict_t *ent) ! 926: { ! 927: if (ent->prethink) ! 928: ent->prethink (ent); ! 929: ! 930: switch ( (int)ent->movetype) ! 931: { ! 932: case MOVETYPE_PUSH: ! 933: case MOVETYPE_STOP: ! 934: SV_Physics_Pusher (ent); ! 935: break; ! 936: case MOVETYPE_NONE: ! 937: SV_Physics_None (ent); ! 938: break; ! 939: case MOVETYPE_NOCLIP: ! 940: SV_Physics_Noclip (ent); ! 941: break; ! 942: case MOVETYPE_STEP: ! 943: SV_Physics_Step (ent); ! 944: break; ! 945: case MOVETYPE_TOSS: ! 946: case MOVETYPE_BOUNCE: ! 947: case MOVETYPE_FLY: ! 948: case MOVETYPE_FLYMISSILE: ! 949: // RAFAEL ! 950: case MOVETYPE_WALLBOUNCE: ! 951: SV_Physics_Toss (ent); ! 952: break; ! 953: default: ! 954: gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype); ! 955: } ! 956: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.