|
|
1.1 ! root 1: // m_move.c -- monster movement ! 2: ! 3: #include "g_local.h" ! 4: ! 5: #define STEPSIZE 18 ! 6: ! 7: // this is used for communications out of sv_movestep to say what entity ! 8: // is blocking us ! 9: edict_t *new_bad; //pmm ! 10: ! 11: /* ! 12: ============= ! 13: M_CheckBottom ! 14: ! 15: Returns false if any part of the bottom of the entity is off an edge that ! 16: is not a staircase. ! 17: ! 18: ============= ! 19: */ ! 20: int c_yes, c_no; ! 21: ! 22: qboolean M_CheckBottom (edict_t *ent) ! 23: { ! 24: vec3_t mins, maxs, start, stop; ! 25: trace_t trace; ! 26: int x, y; ! 27: float mid, bottom; ! 28: ! 29: VectorAdd (ent->s.origin, ent->mins, mins); ! 30: VectorAdd (ent->s.origin, ent->maxs, maxs); ! 31: ! 32: // if all of the points under the corners are solid world, don't bother ! 33: // with the tougher checks ! 34: // the corners must be within 16 of the midpoint ! 35: ! 36: //PGM ! 37: #ifdef ROGUE_GRAVITY ! 38: // FIXME - this will only handle 0,0,1 and 0,0,-1 gravity vectors ! 39: start[2] = mins[2] - 1; ! 40: if(ent->gravityVector[2] > 0) ! 41: start[2] = maxs[2] + 1; ! 42: #else ! 43: start[2] = mins[2] - 1; ! 44: #endif ! 45: //PGM ! 46: ! 47: for (x=0 ; x<=1 ; x++) ! 48: for (y=0 ; y<=1 ; y++) ! 49: { ! 50: start[0] = x ? maxs[0] : mins[0]; ! 51: start[1] = y ? maxs[1] : mins[1]; ! 52: if (gi.pointcontents (start) != CONTENTS_SOLID) ! 53: goto realcheck; ! 54: } ! 55: ! 56: c_yes++; ! 57: return true; // we got out easy ! 58: ! 59: realcheck: ! 60: c_no++; ! 61: // ! 62: // check it for real... ! 63: // ! 64: start[2] = mins[2]; ! 65: ! 66: // the midpoint must be within 16 of the bottom ! 67: start[0] = stop[0] = (mins[0] + maxs[0])*0.5; ! 68: start[1] = stop[1] = (mins[1] + maxs[1])*0.5; ! 69: ! 70: //PGM ! 71: #ifdef ROGUE_GRAVITY ! 72: if(ent->gravityVector[2] < 0) ! 73: { ! 74: start[2] = mins[2]; ! 75: stop[2] = start[2] - STEPSIZE - STEPSIZE; ! 76: } ! 77: else ! 78: { ! 79: start[2] = maxs[2]; ! 80: stop[2] = start[2] + STEPSIZE + STEPSIZE; ! 81: } ! 82: #else ! 83: stop[2] = start[2] - 2*STEPSIZE; ! 84: #endif ! 85: //PGM ! 86: ! 87: trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID); ! 88: ! 89: if (trace.fraction == 1.0) ! 90: return false; ! 91: mid = bottom = trace.endpos[2]; ! 92: ! 93: // the corners must be within 16 of the midpoint ! 94: for (x=0 ; x<=1 ; x++) ! 95: for (y=0 ; y<=1 ; y++) ! 96: { ! 97: start[0] = stop[0] = x ? maxs[0] : mins[0]; ! 98: start[1] = stop[1] = y ? maxs[1] : mins[1]; ! 99: ! 100: trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID); ! 101: ! 102: //PGM ! 103: #ifdef ROGUE_GRAVITY ! 104: // FIXME - this will only handle 0,0,1 and 0,0,-1 gravity vectors ! 105: if(ent->gravityVector[2] > 0) ! 106: { ! 107: if (trace.fraction != 1.0 && trace.endpos[2] < bottom) ! 108: bottom = trace.endpos[2]; ! 109: if (trace.fraction == 1.0 || trace.endpos[2] - mid > STEPSIZE) ! 110: return false; ! 111: } ! 112: else ! 113: { ! 114: if (trace.fraction != 1.0 && trace.endpos[2] > bottom) ! 115: bottom = trace.endpos[2]; ! 116: if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE) ! 117: return false; ! 118: } ! 119: #else ! 120: if (trace.fraction != 1.0 && trace.endpos[2] > bottom) ! 121: bottom = trace.endpos[2]; ! 122: if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE) ! 123: return false; ! 124: #endif ! 125: //PGM ! 126: } ! 127: ! 128: c_yes++; ! 129: return true; ! 130: } ! 131: ! 132: //============ ! 133: // ROGUE ! 134: qboolean IsBadAhead (edict_t *self, edict_t *bad) ! 135: { ! 136: vec3_t dir; ! 137: vec3_t forward; ! 138: ! 139: VectorSubtract (bad->s.origin, self->s.origin, dir); ! 140: VectorNormalize (dir); ! 141: AngleVectors (self->s.angles, forward, NULL, NULL); ! 142: if(DotProduct(forward, dir) > 0) ! 143: { ! 144: // gi.dprintf ("bad ahead...\n"); ! 145: return true; ! 146: } ! 147: ! 148: // gi.dprintf ("bad behind...\n"); ! 149: return false; ! 150: } ! 151: // ROGUE ! 152: //============ ! 153: ! 154: /* ! 155: ============= ! 156: SV_movestep ! 157: ! 158: Called by monster program code. ! 159: The move will be adjusted for slopes and stairs, but if the move isn't ! 160: possible, no move is done, false is returned, and ! 161: pr_global_struct->trace_normal is set to the normal of the blocking wall ! 162: ============= ! 163: */ ! 164: //FIXME since we need to test end position contents here, can we avoid doing ! 165: //it again later in catagorize position? ! 166: qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink) ! 167: { ! 168: float dz; ! 169: vec3_t oldorg, neworg, end; ! 170: trace_t trace; ! 171: int i; ! 172: float stepsize; ! 173: vec3_t test; ! 174: int contents; ! 175: edict_t *current_bad; // PGM ! 176: float minheight; // pmm ! 177: ! 178: //====== ! 179: //PGM ! 180: ! 181: // PMM - who cares about bad areas if you're dead? ! 182: if (ent->health > 0) ! 183: { ! 184: current_bad = CheckForBadArea(ent); ! 185: if(current_bad) ! 186: { ! 187: ent->bad_area = current_bad; ! 188: ! 189: if(ent->enemy && !strcmp(ent->enemy->classname, "tesla")) ! 190: { ! 191: // if the tesla is in front of us, back up... ! 192: if (IsBadAhead (ent, current_bad)) ! 193: VectorScale(move, -1, move); ! 194: } ! 195: } ! 196: else if(ent->bad_area) ! 197: { ! 198: // if we're no longer in a bad area, get back to business. ! 199: ent->bad_area = NULL; ! 200: if(ent->oldenemy)// && ent->bad_area->owner == ent->enemy) ! 201: { ! 202: // gi.dprintf("resuming being pissed at %s\n", ent->oldenemy->classname); ! 203: ent->enemy = ent->oldenemy; ! 204: ent->goalentity = ent->oldenemy; ! 205: FoundTarget(ent); ! 206: // FIXME - remove this when ready!!! ! 207: if (ent->lastMoveTime == level.time) ! 208: if ((g_showlogic) && (g_showlogic->value)) ! 209: gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname); ! 210: ent->lastMoveTime = level.time; ! 211: // FIXME ! 212: ! 213: return true; ! 214: } ! 215: } ! 216: } ! 217: //PGM ! 218: //====== ! 219: ! 220: // try the move ! 221: VectorCopy (ent->s.origin, oldorg); ! 222: VectorAdd (ent->s.origin, move, neworg); ! 223: ! 224: // flying monsters don't step up ! 225: if ( ent->flags & (FL_SWIM | FL_FLY) ) ! 226: { ! 227: // try one move with vertical motion, then one without ! 228: for (i=0 ; i<2 ; i++) ! 229: { ! 230: VectorAdd (ent->s.origin, move, neworg); ! 231: if (i == 0 && ent->enemy) ! 232: { ! 233: if (!ent->goalentity) ! 234: ent->goalentity = ent->enemy; ! 235: dz = ent->s.origin[2] - ent->goalentity->s.origin[2]; ! 236: if (ent->goalentity->client) ! 237: { ! 238: // we want the carrier to stay a certain distance off the ground, to help prevent him ! 239: // from shooting his fliers, who spawn in below him ! 240: // ! 241: if (!strcmp(ent->classname, "monster_carrier")) ! 242: minheight = 104; ! 243: else ! 244: minheight = 40; ! 245: // if (dz > 40) ! 246: if (dz > minheight) ! 247: // pmm ! 248: neworg[2] -= 8; ! 249: if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2))) ! 250: if (dz < (minheight - 10)) ! 251: neworg[2] += 8; ! 252: } ! 253: else ! 254: { ! 255: if (dz > 8) ! 256: neworg[2] -= 8; ! 257: else if (dz > 0) ! 258: neworg[2] -= dz; ! 259: else if (dz < -8) ! 260: neworg[2] += 8; ! 261: else ! 262: neworg[2] += dz; ! 263: } ! 264: } ! 265: ! 266: trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID); ! 267: ! 268: // fly monsters don't enter water voluntarily ! 269: if (ent->flags & FL_FLY) ! 270: { ! 271: if (!ent->waterlevel) ! 272: { ! 273: test[0] = trace.endpos[0]; ! 274: test[1] = trace.endpos[1]; ! 275: test[2] = trace.endpos[2] + ent->mins[2] + 1; ! 276: contents = gi.pointcontents(test); ! 277: if (contents & MASK_WATER) ! 278: return false; ! 279: } ! 280: } ! 281: ! 282: // swim monsters don't exit water voluntarily ! 283: if (ent->flags & FL_SWIM) ! 284: { ! 285: if (ent->waterlevel < 2) ! 286: { ! 287: test[0] = trace.endpos[0]; ! 288: test[1] = trace.endpos[1]; ! 289: test[2] = trace.endpos[2] + ent->mins[2] + 1; ! 290: contents = gi.pointcontents(test); ! 291: if (!(contents & MASK_WATER)) ! 292: return false; ! 293: } ! 294: } ! 295: ! 296: // if (trace.fraction == 1) ! 297: ! 298: // PMM - changed above to this ! 299: if ((trace.fraction == 1) && (!trace.allsolid) && (!trace.startsolid)) ! 300: { ! 301: VectorCopy (trace.endpos, ent->s.origin); ! 302: //===== ! 303: //PGM ! 304: if(!current_bad && CheckForBadArea(ent)) ! 305: { ! 306: // gi.dprintf("Oooh! Bad Area!\n"); ! 307: VectorCopy (oldorg, ent->s.origin); ! 308: } ! 309: else ! 310: { ! 311: if (relink) ! 312: { ! 313: gi.linkentity (ent); ! 314: G_TouchTriggers (ent); ! 315: } ! 316: // FIXME - remove this when ready!!! ! 317: if (ent->lastMoveTime == level.time) ! 318: if ((g_showlogic) && (g_showlogic->value)) ! 319: gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname); ! 320: ent->lastMoveTime = level.time; ! 321: // FIXME ! 322: ! 323: return true; ! 324: } ! 325: //PGM ! 326: //===== ! 327: } ! 328: ! 329: if (!ent->enemy) ! 330: break; ! 331: } ! 332: ! 333: return false; ! 334: } ! 335: ! 336: // push down from a step height above the wished position ! 337: if (!(ent->monsterinfo.aiflags & AI_NOSTEP)) ! 338: stepsize = STEPSIZE; ! 339: else ! 340: stepsize = 1; ! 341: ! 342: //PGM ! 343: #ifdef ROGUE_GRAVITY ! 344: // trace from 1 stepsize gravityUp to 2 stepsize gravityDown. ! 345: VectorMA(neworg, -1 * stepsize, ent->gravityVector, neworg); ! 346: VectorMA(neworg, 2 * stepsize, ent->gravityVector, end); ! 347: #else ! 348: neworg[2] += stepsize; ! 349: VectorCopy (neworg, end); ! 350: end[2] -= stepsize*2; ! 351: #endif ! 352: //PGM ! 353: ! 354: trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); ! 355: ! 356: if (trace.allsolid) ! 357: return false; ! 358: ! 359: if (trace.startsolid) ! 360: { ! 361: neworg[2] -= stepsize; ! 362: trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); ! 363: if (trace.allsolid || trace.startsolid) ! 364: return false; ! 365: } ! 366: ! 367: ! 368: // don't go in to water ! 369: if (ent->waterlevel == 0) ! 370: { ! 371: //PGM ! 372: #ifdef ROGUE_GRAVITY ! 373: test[0] = trace.endpos[0]; ! 374: test[1] = trace.endpos[1]; ! 375: if(ent->gravityVector[2] > 0) ! 376: test[2] = trace.endpos[2] + ent->maxs[2] - 1; ! 377: else ! 378: test[2] = trace.endpos[2] + ent->mins[2] + 1; ! 379: #else ! 380: test[0] = trace.endpos[0]; ! 381: test[1] = trace.endpos[1]; ! 382: test[2] = trace.endpos[2] + ent->mins[2] + 1; ! 383: #endif ! 384: //PGM ! 385: ! 386: contents = gi.pointcontents(test); ! 387: ! 388: if (contents & MASK_WATER) ! 389: return false; ! 390: } ! 391: ! 392: if (trace.fraction == 1) ! 393: { ! 394: // if monster had the ground pulled out, go ahead and fall ! 395: if ( ent->flags & FL_PARTIALGROUND ) ! 396: { ! 397: VectorAdd (ent->s.origin, move, ent->s.origin); ! 398: if (relink) ! 399: { ! 400: gi.linkentity (ent); ! 401: G_TouchTriggers (ent); ! 402: } ! 403: ent->groundentity = NULL; ! 404: // FIXME - remove this when ready!!! ! 405: if (ent->lastMoveTime == level.time) ! 406: if ((g_showlogic) && (g_showlogic->value)) ! 407: gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname); ! 408: ent->lastMoveTime = level.time; ! 409: // FIXME ! 410: ! 411: return true; ! 412: } ! 413: ! 414: return false; // walked off an edge ! 415: } ! 416: ! 417: // check point traces down for dangling corners ! 418: VectorCopy (trace.endpos, ent->s.origin); ! 419: ! 420: //PGM ! 421: // PMM - don't bother with bad areas if we're dead ! 422: if (ent->health > 0) ! 423: { ! 424: // use AI_BLOCKED to tell the calling layer that we're now mad at a tesla ! 425: new_bad = CheckForBadArea(ent); ! 426: if(!current_bad && new_bad) ! 427: { ! 428: if (new_bad->owner) ! 429: { ! 430: if ((g_showlogic) && (g_showlogic->value)) ! 431: gi.dprintf("Blocked -"); ! 432: if (!strcmp(new_bad->owner->classname, "tesla")) ! 433: { ! 434: if ((g_showlogic) && (g_showlogic->value)) ! 435: gi.dprintf ("it's a tesla -"); ! 436: if ((!(ent->enemy)) || (!(ent->enemy->inuse))) ! 437: { ! 438: if ((g_showlogic) && (g_showlogic->value)) ! 439: gi.dprintf ("I don't have a valid enemy, attacking tesla!\n"); ! 440: TargetTesla (ent, new_bad->owner); ! 441: ent->monsterinfo.aiflags |= AI_BLOCKED; ! 442: } ! 443: else if (!strcmp(ent->enemy->classname, "telsa")) ! 444: { ! 445: if ((g_showlogic) && (g_showlogic->value)) ! 446: gi.dprintf ("but we're already mad at a tesla\n"); ! 447: } ! 448: else if ((ent->enemy) && (ent->enemy->client)) ! 449: { ! 450: if ((g_showlogic) && (g_showlogic->value)) ! 451: gi.dprintf ("we have a player enemy -"); ! 452: if (visible(ent, ent->enemy)) ! 453: { ! 454: if ((g_showlogic) && (g_showlogic->value)) ! 455: gi.dprintf ("we can see him -"); ! 456: } ! 457: else ! 458: { ! 459: if ((g_showlogic) && (g_showlogic->value)) ! 460: gi.dprintf ("can't see him, kill the tesla! -"); ! 461: TargetTesla (ent, new_bad->owner); ! 462: ent->monsterinfo.aiflags |= AI_BLOCKED; ! 463: } ! 464: } ! 465: else ! 466: { ! 467: if ((g_showlogic) && (g_showlogic->value)) ! 468: gi.dprintf ("the enemy isn't a player, killing tesla -"); ! 469: TargetTesla (ent, new_bad->owner); ! 470: ent->monsterinfo.aiflags |= AI_BLOCKED; ! 471: } ! 472: } ! 473: else if ((g_showlogic) && (g_showlogic->value)) ! 474: { ! 475: gi.dprintf(" by non-tesla bad area!"); ! 476: } ! 477: } ! 478: gi.dprintf ("\n"); ! 479: ! 480: VectorCopy (oldorg, ent->s.origin); ! 481: return false; ! 482: } ! 483: } ! 484: //PGM ! 485: ! 486: if (!M_CheckBottom (ent)) ! 487: { ! 488: if ( ent->flags & FL_PARTIALGROUND ) ! 489: { // entity had floor mostly pulled out from underneath it ! 490: // and is trying to correct ! 491: if (relink) ! 492: { ! 493: gi.linkentity (ent); ! 494: G_TouchTriggers (ent); ! 495: } ! 496: // FIXME - remove this when ready!!! ! 497: if (ent->lastMoveTime == level.time) ! 498: if ((g_showlogic) && (g_showlogic->value)) ! 499: gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname); ! 500: ent->lastMoveTime = level.time; ! 501: // FIXME ! 502: ! 503: return true; ! 504: } ! 505: VectorCopy (oldorg, ent->s.origin); ! 506: return false; ! 507: } ! 508: ! 509: if ( ent->flags & FL_PARTIALGROUND ) ! 510: { ! 511: ent->flags &= ~FL_PARTIALGROUND; ! 512: } ! 513: ent->groundentity = trace.ent; ! 514: ent->groundentity_linkcount = trace.ent->linkcount; ! 515: ! 516: // the move is ok ! 517: if (relink) ! 518: { ! 519: gi.linkentity (ent); ! 520: G_TouchTriggers (ent); ! 521: } ! 522: // FIXME - remove this when ready!!! ! 523: if (ent->lastMoveTime == level.time) ! 524: if ((g_showlogic) && (g_showlogic->value)) ! 525: gi.dprintf ("Duplicate move detected for %s, please tell programmers!\n", ent->classname); ! 526: ent->lastMoveTime = level.time; ! 527: // FIXME ! 528: ! 529: return true; ! 530: } ! 531: ! 532: ! 533: //============================================================================ ! 534: ! 535: /* ! 536: =============== ! 537: M_ChangeYaw ! 538: ! 539: =============== ! 540: */ ! 541: void M_ChangeYaw (edict_t *ent) ! 542: { ! 543: float ideal; ! 544: float current; ! 545: float move; ! 546: float speed; ! 547: ! 548: current = anglemod(ent->s.angles[YAW]); ! 549: ideal = ent->ideal_yaw; ! 550: ! 551: if (current == ideal) ! 552: return; ! 553: ! 554: move = ideal - current; ! 555: speed = ent->yaw_speed; ! 556: if (ideal > current) ! 557: { ! 558: if (move >= 180) ! 559: move = move - 360; ! 560: } ! 561: else ! 562: { ! 563: if (move <= -180) ! 564: move = move + 360; ! 565: } ! 566: if (move > 0) ! 567: { ! 568: if (move > speed) ! 569: move = speed; ! 570: } ! 571: else ! 572: { ! 573: if (move < -speed) ! 574: move = -speed; ! 575: } ! 576: ! 577: ent->s.angles[YAW] = anglemod (current + move); ! 578: } ! 579: ! 580: ! 581: /* ! 582: ====================== ! 583: SV_StepDirection ! 584: ! 585: Turns to the movement direction, and walks the current distance if ! 586: facing it. ! 587: ! 588: ====================== ! 589: */ ! 590: qboolean SV_StepDirection (edict_t *ent, float yaw, float dist) ! 591: { ! 592: vec3_t move, oldorigin; ! 593: float delta; ! 594: ! 595: if(!ent->inuse) return true; // PGM g_touchtrigger free problem ! 596: ! 597: ent->ideal_yaw = yaw; ! 598: M_ChangeYaw (ent); ! 599: ! 600: yaw = yaw*M_PI*2 / 360; ! 601: move[0] = cos(yaw)*dist; ! 602: move[1] = sin(yaw)*dist; ! 603: move[2] = 0; ! 604: ! 605: VectorCopy (ent->s.origin, oldorigin); ! 606: if (SV_movestep (ent, move, false)) ! 607: { ! 608: ent->monsterinfo.aiflags &= ~AI_BLOCKED; ! 609: if(!ent->inuse) return true; // PGM g_touchtrigger free problem ! 610: ! 611: delta = ent->s.angles[YAW] - ent->ideal_yaw; ! 612: if (strncmp(ent->classname, "monster_widow", 13)) ! 613: { ! 614: if (delta > 45 && delta < 315) ! 615: { // not turned far enough, so don't take the step ! 616: VectorCopy (oldorigin, ent->s.origin); ! 617: } ! 618: } ! 619: gi.linkentity (ent); ! 620: G_TouchTriggers (ent); ! 621: return true; ! 622: } ! 623: gi.linkentity (ent); ! 624: G_TouchTriggers (ent); ! 625: return false; ! 626: } ! 627: ! 628: /* ! 629: ====================== ! 630: SV_FixCheckBottom ! 631: ! 632: ====================== ! 633: */ ! 634: void SV_FixCheckBottom (edict_t *ent) ! 635: { ! 636: ent->flags |= FL_PARTIALGROUND; ! 637: } ! 638: ! 639: ! 640: ! 641: /* ! 642: ================ ! 643: SV_NewChaseDir ! 644: ! 645: ================ ! 646: */ ! 647: #define DI_NODIR -1 ! 648: void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist) ! 649: { ! 650: float deltax,deltay; ! 651: float d[3]; ! 652: float tdir, olddir, turnaround; ! 653: ! 654: //FIXME: how did we get here with no enemy ! 655: if (!enemy) ! 656: return; ! 657: ! 658: olddir = anglemod( (int)(actor->ideal_yaw/45)*45 ); ! 659: turnaround = anglemod(olddir - 180); ! 660: ! 661: deltax = enemy->s.origin[0] - actor->s.origin[0]; ! 662: deltay = enemy->s.origin[1] - actor->s.origin[1]; ! 663: if (deltax>10) ! 664: d[1]= 0; ! 665: else if (deltax<-10) ! 666: d[1]= 180; ! 667: else ! 668: d[1]= DI_NODIR; ! 669: if (deltay<-10) ! 670: d[2]= 270; ! 671: else if (deltay>10) ! 672: d[2]= 90; ! 673: else ! 674: d[2]= DI_NODIR; ! 675: ! 676: // try direct route ! 677: if (d[1] != DI_NODIR && d[2] != DI_NODIR) ! 678: { ! 679: if (d[1] == 0) ! 680: tdir = d[2] == 90 ? 45 : 315; ! 681: else ! 682: tdir = d[2] == 90 ? 135 : 215; ! 683: ! 684: if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) ! 685: return; ! 686: } ! 687: ! 688: // try other directions ! 689: if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax)) ! 690: { ! 691: tdir=d[1]; ! 692: d[1]=d[2]; ! 693: d[2]=tdir; ! 694: } ! 695: ! 696: if (d[1]!=DI_NODIR && d[1]!=turnaround ! 697: && SV_StepDirection(actor, d[1], dist)) ! 698: return; ! 699: ! 700: if (d[2]!=DI_NODIR && d[2]!=turnaround ! 701: && SV_StepDirection(actor, d[2], dist)) ! 702: return; ! 703: ! 704: //ROGUE ! 705: if(actor->monsterinfo.blocked) ! 706: { ! 707: if ((actor->inuse) && (actor->health > 0)) ! 708: { ! 709: if((actor->monsterinfo.blocked)(actor, dist)) ! 710: return; ! 711: } ! 712: } ! 713: //ROGUE ! 714: ! 715: /* there is no direct path to the player, so pick another direction */ ! 716: ! 717: if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist)) ! 718: return; ! 719: ! 720: if (rand()&1) /*randomly determine direction of search*/ ! 721: { ! 722: for (tdir=0 ; tdir<=315 ; tdir += 45) ! 723: if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) ! 724: return; ! 725: } ! 726: else ! 727: { ! 728: for (tdir=315 ; tdir >=0 ; tdir -= 45) ! 729: if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) ! 730: return; ! 731: } ! 732: ! 733: if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) ) ! 734: return; ! 735: ! 736: actor->ideal_yaw = olddir; // can't move ! 737: ! 738: // if a bridge was pulled out from underneath a monster, it may not have ! 739: // a valid standing position at all ! 740: ! 741: if (!M_CheckBottom (actor)) ! 742: SV_FixCheckBottom (actor); ! 743: } ! 744: ! 745: /* ! 746: ====================== ! 747: SV_CloseEnough ! 748: ! 749: ====================== ! 750: */ ! 751: qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist) ! 752: { ! 753: int i; ! 754: ! 755: for (i=0 ; i<3 ; i++) ! 756: { ! 757: if (goal->absmin[i] > ent->absmax[i] + dist) ! 758: return false; ! 759: if (goal->absmax[i] < ent->absmin[i] - dist) ! 760: return false; ! 761: } ! 762: return true; ! 763: } ! 764: ! 765: /* ! 766: ====================== ! 767: M_MoveToGoal ! 768: ====================== ! 769: */ ! 770: void M_MoveToGoal (edict_t *ent, float dist) ! 771: { ! 772: edict_t *goal; ! 773: ! 774: goal = ent->goalentity; ! 775: ! 776: if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM))) ! 777: return; ! 778: ! 779: // if the next step hits the enemy, return immediately ! 780: if (ent->enemy && SV_CloseEnough (ent, ent->enemy, dist) ) ! 781: return; ! 782: ! 783: // bump around... ! 784: // if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->ideal_yaw, dist)) ! 785: // PMM - charging monsters (AI_CHARGING) don't deflect unless they have to ! 786: if ( (((rand()&3)==1) && !(ent->monsterinfo.aiflags & AI_CHARGING)) || !SV_StepDirection (ent, ent->ideal_yaw, dist)) ! 787: { ! 788: if (ent->monsterinfo.aiflags & AI_BLOCKED) ! 789: { ! 790: if ((g_showlogic) && (g_showlogic->value)) ! 791: gi.dprintf ("tesla attack detected, not changing direction!\n"); ! 792: ent->monsterinfo.aiflags &= ~AI_BLOCKED; ! 793: return; ! 794: } ! 795: if (ent->inuse) ! 796: SV_NewChaseDir (ent, goal, dist); ! 797: } ! 798: } ! 799: ! 800: ! 801: /* ! 802: =============== ! 803: M_walkmove ! 804: =============== ! 805: */ ! 806: qboolean M_walkmove (edict_t *ent, float yaw, float dist) ! 807: { ! 808: vec3_t move; ! 809: // PMM ! 810: qboolean retval; ! 811: ! 812: if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM))) ! 813: return false; ! 814: ! 815: yaw = yaw*M_PI*2 / 360; ! 816: ! 817: move[0] = cos(yaw)*dist; ! 818: move[1] = sin(yaw)*dist; ! 819: move[2] = 0; ! 820: ! 821: // PMM ! 822: retval = SV_movestep(ent, move, true); ! 823: ent->monsterinfo.aiflags &= ~AI_BLOCKED; ! 824: return retval; ! 825: // pmm ! 826: //return SV_movestep(ent, move, true); ! 827: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.