|
|
1.1 ! root 1: // m_move.c -- monster movement ! 2: ! 3: #include "g_local.h" ! 4: ! 5: #define STEPSIZE 18 ! 6: ! 7: /* ! 8: ============= ! 9: M_CheckBottom ! 10: ! 11: Returns false if any part of the bottom of the entity is off an edge that ! 12: is not a staircase. ! 13: ! 14: ============= ! 15: */ ! 16: int c_yes, c_no; ! 17: ! 18: qboolean M_CheckBottom (edict_t *ent) ! 19: { ! 20: vec3_t mins, maxs, start, stop; ! 21: trace_t trace; ! 22: int x, y; ! 23: float mid, bottom; ! 24: ! 25: VectorAdd (ent->s.origin, ent->mins, mins); ! 26: VectorAdd (ent->s.origin, ent->maxs, maxs); ! 27: ! 28: // if all of the points under the corners are solid world, don't bother ! 29: // with the tougher checks ! 30: // the corners must be within 16 of the midpoint ! 31: start[2] = mins[2] - 1; ! 32: for (x=0 ; x<=1 ; x++) ! 33: for (y=0 ; y<=1 ; y++) ! 34: { ! 35: start[0] = x ? maxs[0] : mins[0]; ! 36: start[1] = y ? maxs[1] : mins[1]; ! 37: if (gi.pointcontents (start) != CONTENTS_SOLID) ! 38: goto realcheck; ! 39: } ! 40: ! 41: c_yes++; ! 42: return true; // we got out easy ! 43: ! 44: realcheck: ! 45: c_no++; ! 46: // ! 47: // check it for real... ! 48: // ! 49: start[2] = mins[2]; ! 50: ! 51: // the midpoint must be within 16 of the bottom ! 52: start[0] = stop[0] = (mins[0] + maxs[0])*0.5; ! 53: start[1] = stop[1] = (mins[1] + maxs[1])*0.5; ! 54: stop[2] = start[2] - 2*STEPSIZE; ! 55: trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID); ! 56: ! 57: if (trace.fraction == 1.0) ! 58: return false; ! 59: mid = bottom = trace.endpos[2]; ! 60: ! 61: // the corners must be within 16 of the midpoint ! 62: for (x=0 ; x<=1 ; x++) ! 63: for (y=0 ; y<=1 ; y++) ! 64: { ! 65: start[0] = stop[0] = x ? maxs[0] : mins[0]; ! 66: start[1] = stop[1] = y ? maxs[1] : mins[1]; ! 67: ! 68: trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID); ! 69: ! 70: if (trace.fraction != 1.0 && trace.endpos[2] > bottom) ! 71: bottom = trace.endpos[2]; ! 72: if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE) ! 73: return false; ! 74: } ! 75: ! 76: c_yes++; ! 77: return true; ! 78: } ! 79: ! 80: ! 81: /* ! 82: ============= ! 83: SV_movestep ! 84: ! 85: Called by monster program code. ! 86: The move will be adjusted for slopes and stairs, but if the move isn't ! 87: possible, no move is done, false is returned, and ! 88: pr_global_struct->trace_normal is set to the normal of the blocking wall ! 89: ============= ! 90: */ ! 91: //FIXME since we need to test end position contents here, can we avoid doing ! 92: //it again later in catagorize position? ! 93: qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink) ! 94: { ! 95: float dz; ! 96: vec3_t oldorg, neworg, end; ! 97: trace_t trace; ! 98: int i; ! 99: float stepsize; ! 100: vec3_t test; ! 101: int contents; ! 102: ! 103: // try the move ! 104: VectorCopy (ent->s.origin, oldorg); ! 105: VectorAdd (ent->s.origin, move, neworg); ! 106: ! 107: // flying monsters don't step up ! 108: if ( ent->flags & (FL_SWIM | FL_FLY) ) ! 109: { ! 110: // try one move with vertical motion, then one without ! 111: for (i=0 ; i<2 ; i++) ! 112: { ! 113: VectorAdd (ent->s.origin, move, neworg); ! 114: if (i == 0 && ent->enemy) ! 115: { ! 116: if (!ent->goalentity) ! 117: ent->goalentity = ent->enemy; ! 118: dz = ent->s.origin[2] - ent->goalentity->s.origin[2]; ! 119: if (ent->goalentity->client) ! 120: { ! 121: if (dz > 40) ! 122: neworg[2] -= 8; ! 123: if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2))) ! 124: if (dz < 30) ! 125: neworg[2] += 8; ! 126: } ! 127: else ! 128: { ! 129: // RAFAEL ! 130: if (strcmp (ent->classname , "monster_fixbot") == 0) ! 131: { ! 132: if (ent->s.frame >= 105 && ent->s.frame <= 120) ! 133: { ! 134: if (dz > 12) ! 135: neworg[2] --; ! 136: else if (dz < -12) ! 137: neworg[2] ++; ! 138: } ! 139: else if (ent->s.frame >= 31 && ent->s.frame <= 88) ! 140: { ! 141: if (dz > 12) ! 142: neworg[2] -= 12; ! 143: else if (dz < -12) ! 144: neworg[2] += 12; ! 145: } ! 146: else ! 147: { ! 148: if (dz > 12) ! 149: neworg[2] -= 8; ! 150: else if (dz < -12) ! 151: neworg[2] += 8; ! 152: } ! 153: } ! 154: // RAFAEL ( else ) ! 155: else ! 156: { ! 157: if (dz > 8) ! 158: neworg[2] -= 8; ! 159: else if (dz > 0) ! 160: neworg[2] -= dz; ! 161: else if (dz < -8) ! 162: neworg[2] += 8; ! 163: else ! 164: neworg[2] += dz; ! 165: } ! 166: } ! 167: } ! 168: trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID); ! 169: ! 170: // fly monsters don't enter water voluntarily ! 171: if (ent->flags & FL_FLY) ! 172: { ! 173: if (!ent->waterlevel) ! 174: { ! 175: test[0] = trace.endpos[0]; ! 176: test[1] = trace.endpos[1]; ! 177: test[2] = trace.endpos[2] + ent->mins[2] + 1; ! 178: contents = gi.pointcontents(test); ! 179: if (contents & MASK_WATER) ! 180: return false; ! 181: } ! 182: } ! 183: ! 184: // swim monsters don't exit water voluntarily ! 185: if (ent->flags & FL_SWIM) ! 186: { ! 187: if (ent->waterlevel < 2) ! 188: { ! 189: test[0] = trace.endpos[0]; ! 190: test[1] = trace.endpos[1]; ! 191: test[2] = trace.endpos[2] + ent->mins[2] + 1; ! 192: contents = gi.pointcontents(test); ! 193: if (!(contents & MASK_WATER)) ! 194: return false; ! 195: } ! 196: } ! 197: ! 198: if (trace.fraction == 1) ! 199: { ! 200: VectorCopy (trace.endpos, ent->s.origin); ! 201: if (relink) ! 202: { ! 203: gi.linkentity (ent); ! 204: G_TouchTriggers (ent); ! 205: } ! 206: return true; ! 207: } ! 208: ! 209: if (!ent->enemy) ! 210: break; ! 211: } ! 212: ! 213: return false; ! 214: } ! 215: ! 216: // push down from a step height above the wished position ! 217: if (!(ent->monsterinfo.aiflags & AI_NOSTEP)) ! 218: stepsize = STEPSIZE; ! 219: else ! 220: stepsize = 1; ! 221: ! 222: neworg[2] += stepsize; ! 223: VectorCopy (neworg, end); ! 224: end[2] -= stepsize*2; ! 225: ! 226: trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); ! 227: ! 228: if (trace.allsolid) ! 229: return false; ! 230: ! 231: if (trace.startsolid) ! 232: { ! 233: neworg[2] -= stepsize; ! 234: trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); ! 235: if (trace.allsolid || trace.startsolid) ! 236: return false; ! 237: } ! 238: ! 239: ! 240: // don't go in to water ! 241: if (ent->waterlevel == 0) ! 242: { ! 243: test[0] = trace.endpos[0]; ! 244: test[1] = trace.endpos[1]; ! 245: test[2] = trace.endpos[2] + ent->mins[2] + 1; ! 246: contents = gi.pointcontents(test); ! 247: ! 248: if (contents & MASK_WATER) ! 249: return false; ! 250: } ! 251: ! 252: if (trace.fraction == 1) ! 253: { ! 254: // if monster had the ground pulled out, go ahead and fall ! 255: if ( ent->flags & FL_PARTIALGROUND ) ! 256: { ! 257: VectorAdd (ent->s.origin, move, ent->s.origin); ! 258: if (relink) ! 259: { ! 260: gi.linkentity (ent); ! 261: G_TouchTriggers (ent); ! 262: } ! 263: ent->groundentity = NULL; ! 264: return true; ! 265: } ! 266: ! 267: return false; // walked off an edge ! 268: } ! 269: ! 270: // check point traces down for dangling corners ! 271: VectorCopy (trace.endpos, ent->s.origin); ! 272: ! 273: if (!M_CheckBottom (ent)) ! 274: { ! 275: if ( ent->flags & FL_PARTIALGROUND ) ! 276: { // entity had floor mostly pulled out from underneath it ! 277: // and is trying to correct ! 278: if (relink) ! 279: { ! 280: gi.linkentity (ent); ! 281: G_TouchTriggers (ent); ! 282: } ! 283: return true; ! 284: } ! 285: VectorCopy (oldorg, ent->s.origin); ! 286: return false; ! 287: } ! 288: ! 289: if ( ent->flags & FL_PARTIALGROUND ) ! 290: { ! 291: ent->flags &= ~FL_PARTIALGROUND; ! 292: } ! 293: ent->groundentity = trace.ent; ! 294: ent->groundentity_linkcount = trace.ent->linkcount; ! 295: ! 296: // the move is ok ! 297: if (relink) ! 298: { ! 299: gi.linkentity (ent); ! 300: G_TouchTriggers (ent); ! 301: } ! 302: return true; ! 303: } ! 304: ! 305: ! 306: //============================================================================ ! 307: ! 308: /* ! 309: =============== ! 310: M_ChangeYaw ! 311: ! 312: =============== ! 313: */ ! 314: void M_ChangeYaw (edict_t *ent) ! 315: { ! 316: float ideal; ! 317: float current; ! 318: float move; ! 319: float speed; ! 320: ! 321: current = anglemod(ent->s.angles[YAW]); ! 322: ideal = ent->ideal_yaw; ! 323: ! 324: if (current == ideal) ! 325: return; ! 326: ! 327: move = ideal - current; ! 328: speed = ent->yaw_speed; ! 329: if (ideal > current) ! 330: { ! 331: if (move >= 180) ! 332: move = move - 360; ! 333: } ! 334: else ! 335: { ! 336: if (move <= -180) ! 337: move = move + 360; ! 338: } ! 339: if (move > 0) ! 340: { ! 341: if (move > speed) ! 342: move = speed; ! 343: } ! 344: else ! 345: { ! 346: if (move < -speed) ! 347: move = -speed; ! 348: } ! 349: ! 350: ent->s.angles[YAW] = anglemod (current + move); ! 351: } ! 352: ! 353: ! 354: /* ! 355: ====================== ! 356: SV_StepDirection ! 357: ! 358: Turns to the movement direction, and walks the current distance if ! 359: facing it. ! 360: ! 361: ====================== ! 362: */ ! 363: qboolean SV_StepDirection (edict_t *ent, float yaw, float dist) ! 364: { ! 365: vec3_t move, oldorigin; ! 366: float delta; ! 367: ! 368: ent->ideal_yaw = yaw; ! 369: M_ChangeYaw (ent); ! 370: ! 371: yaw = yaw*M_PI*2 / 360; ! 372: move[0] = cos(yaw)*dist; ! 373: move[1] = sin(yaw)*dist; ! 374: move[2] = 0; ! 375: ! 376: VectorCopy (ent->s.origin, oldorigin); ! 377: if (SV_movestep (ent, move, false)) ! 378: { ! 379: delta = ent->s.angles[YAW] - ent->ideal_yaw; ! 380: if (delta > 45 && delta < 315) ! 381: { // not turned far enough, so don't take the step ! 382: VectorCopy (oldorigin, ent->s.origin); ! 383: } ! 384: gi.linkentity (ent); ! 385: G_TouchTriggers (ent); ! 386: return true; ! 387: } ! 388: gi.linkentity (ent); ! 389: G_TouchTriggers (ent); ! 390: return false; ! 391: } ! 392: ! 393: /* ! 394: ====================== ! 395: SV_FixCheckBottom ! 396: ! 397: ====================== ! 398: */ ! 399: void SV_FixCheckBottom (edict_t *ent) ! 400: { ! 401: ent->flags |= FL_PARTIALGROUND; ! 402: } ! 403: ! 404: ! 405: ! 406: /* ! 407: ================ ! 408: SV_NewChaseDir ! 409: ! 410: ================ ! 411: */ ! 412: #define DI_NODIR -1 ! 413: void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist) ! 414: { ! 415: float deltax,deltay; ! 416: float d[3]; ! 417: float tdir, olddir, turnaround; ! 418: ! 419: //FIXME: how did we get here with no enemy ! 420: if (!enemy) ! 421: return; ! 422: ! 423: olddir = anglemod( (int)(actor->ideal_yaw/45)*45 ); ! 424: turnaround = anglemod(olddir - 180); ! 425: ! 426: deltax = enemy->s.origin[0] - actor->s.origin[0]; ! 427: deltay = enemy->s.origin[1] - actor->s.origin[1]; ! 428: if (deltax>10) ! 429: d[1]= 0; ! 430: else if (deltax<-10) ! 431: d[1]= 180; ! 432: else ! 433: d[1]= DI_NODIR; ! 434: if (deltay<-10) ! 435: d[2]= 270; ! 436: else if (deltay>10) ! 437: d[2]= 90; ! 438: else ! 439: d[2]= DI_NODIR; ! 440: ! 441: // try direct route ! 442: if (d[1] != DI_NODIR && d[2] != DI_NODIR) ! 443: { ! 444: if (d[1] == 0) ! 445: tdir = d[2] == 90 ? 45 : 315; ! 446: else ! 447: tdir = d[2] == 90 ? 135 : 215; ! 448: ! 449: if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) ! 450: return; ! 451: } ! 452: ! 453: // try other directions ! 454: if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax)) ! 455: { ! 456: tdir=d[1]; ! 457: d[1]=d[2]; ! 458: d[2]=tdir; ! 459: } ! 460: ! 461: if (d[1]!=DI_NODIR && d[1]!=turnaround ! 462: && SV_StepDirection(actor, d[1], dist)) ! 463: return; ! 464: ! 465: if (d[2]!=DI_NODIR && d[2]!=turnaround ! 466: && SV_StepDirection(actor, d[2], dist)) ! 467: return; ! 468: ! 469: /* there is no direct path to the player, so pick another direction */ ! 470: ! 471: if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist)) ! 472: return; ! 473: ! 474: if (rand()&1) /*randomly determine direction of search*/ ! 475: { ! 476: for (tdir=0 ; tdir<=315 ; tdir += 45) ! 477: if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) ! 478: return; ! 479: } ! 480: else ! 481: { ! 482: for (tdir=315 ; tdir >=0 ; tdir -= 45) ! 483: if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) ! 484: return; ! 485: } ! 486: ! 487: if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) ) ! 488: return; ! 489: ! 490: actor->ideal_yaw = olddir; // can't move ! 491: ! 492: // if a bridge was pulled out from underneath a monster, it may not have ! 493: // a valid standing position at all ! 494: ! 495: if (!M_CheckBottom (actor)) ! 496: SV_FixCheckBottom (actor); ! 497: } ! 498: ! 499: /* ! 500: ====================== ! 501: SV_CloseEnough ! 502: ! 503: ====================== ! 504: */ ! 505: qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist) ! 506: { ! 507: int i; ! 508: ! 509: for (i=0 ; i<3 ; i++) ! 510: { ! 511: if (goal->absmin[i] > ent->absmax[i] + dist) ! 512: return false; ! 513: if (goal->absmax[i] < ent->absmin[i] - dist) ! 514: return false; ! 515: } ! 516: return true; ! 517: } ! 518: ! 519: ! 520: /* ! 521: ====================== ! 522: M_MoveToGoal ! 523: ====================== ! 524: */ ! 525: void M_MoveToGoal (edict_t *ent, float dist) ! 526: { ! 527: edict_t *goal; ! 528: ! 529: goal = ent->goalentity; ! 530: ! 531: if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM))) ! 532: return; ! 533: ! 534: // if the next step hits the enemy, return immediately ! 535: if (ent->enemy && SV_CloseEnough (ent, ent->enemy, dist) ) ! 536: return; ! 537: ! 538: // bump around... ! 539: if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->ideal_yaw, dist)) ! 540: { ! 541: if (ent->inuse) ! 542: SV_NewChaseDir (ent, goal, dist); ! 543: } ! 544: } ! 545: ! 546: ! 547: /* ! 548: =============== ! 549: M_walkmove ! 550: =============== ! 551: */ ! 552: qboolean M_walkmove (edict_t *ent, float yaw, float dist) ! 553: { ! 554: vec3_t move; ! 555: ! 556: if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM))) ! 557: return false; ! 558: ! 559: yaw = yaw*M_PI*2 / 360; ! 560: ! 561: move[0] = cos(yaw)*dist; ! 562: move[1] = sin(yaw)*dist; ! 563: move[2] = 0; ! 564: ! 565: return SV_movestep(ent, move, true); ! 566: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.