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