|
|
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: if (dz > 8) ! 130: neworg[2] -= 8; ! 131: else if (dz > 0) ! 132: neworg[2] -= dz; ! 133: else if (dz < -8) ! 134: neworg[2] += 8; ! 135: else ! 136: neworg[2] += dz; ! 137: } ! 138: } ! 139: trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID); ! 140: ! 141: // fly monsters don't enter water voluntarily ! 142: if (ent->flags & FL_FLY) ! 143: { ! 144: if (!ent->waterlevel) ! 145: { ! 146: test[0] = trace.endpos[0]; ! 147: test[1] = trace.endpos[1]; ! 148: test[2] = trace.endpos[2] + ent->mins[2] + 1; ! 149: contents = gi.pointcontents(test); ! 150: if (contents & MASK_WATER) ! 151: return false; ! 152: } ! 153: } ! 154: ! 155: // swim monsters don't exit water voluntarily ! 156: if (ent->flags & FL_SWIM) ! 157: { ! 158: if (ent->waterlevel < 2) ! 159: { ! 160: test[0] = trace.endpos[0]; ! 161: test[1] = trace.endpos[1]; ! 162: test[2] = trace.endpos[2] + ent->mins[2] + 1; ! 163: contents = gi.pointcontents(test); ! 164: if (!(contents & MASK_WATER)) ! 165: return false; ! 166: } ! 167: } ! 168: ! 169: if (trace.fraction == 1) ! 170: { ! 171: VectorCopy (trace.endpos, ent->s.origin); ! 172: if (relink) ! 173: { ! 174: gi.linkentity (ent); ! 175: G_TouchTriggers (ent); ! 176: } ! 177: return true; ! 178: } ! 179: ! 180: if (!ent->enemy) ! 181: break; ! 182: } ! 183: ! 184: return false; ! 185: } ! 186: ! 187: // push down from a step height above the wished position ! 188: if (!(ent->monsterinfo.aiflags & AI_NOSTEP)) ! 189: stepsize = STEPSIZE; ! 190: else ! 191: stepsize = 1; ! 192: ! 193: neworg[2] += stepsize; ! 194: VectorCopy (neworg, end); ! 195: end[2] -= stepsize*2; ! 196: ! 197: trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); ! 198: ! 199: if (trace.allsolid) ! 200: return false; ! 201: ! 202: if (trace.startsolid) ! 203: { ! 204: neworg[2] -= stepsize; ! 205: trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); ! 206: if (trace.allsolid || trace.startsolid) ! 207: return false; ! 208: } ! 209: ! 210: ! 211: // don't go in to water ! 212: if (ent->waterlevel == 0) ! 213: { ! 214: test[0] = trace.endpos[0]; ! 215: test[1] = trace.endpos[1]; ! 216: test[2] = trace.endpos[2] + ent->mins[2] + 1; ! 217: contents = gi.pointcontents(test); ! 218: ! 219: if (contents & MASK_WATER) ! 220: return false; ! 221: } ! 222: ! 223: if (trace.fraction == 1) ! 224: { ! 225: // if monster had the ground pulled out, go ahead and fall ! 226: if ( ent->flags & FL_PARTIALGROUND ) ! 227: { ! 228: VectorAdd (ent->s.origin, move, ent->s.origin); ! 229: if (relink) ! 230: { ! 231: gi.linkentity (ent); ! 232: G_TouchTriggers (ent); ! 233: } ! 234: ent->groundentity = NULL; ! 235: return true; ! 236: } ! 237: ! 238: return false; // walked off an edge ! 239: } ! 240: ! 241: // check point traces down for dangling corners ! 242: VectorCopy (trace.endpos, ent->s.origin); ! 243: ! 244: if (!M_CheckBottom (ent)) ! 245: { ! 246: if ( ent->flags & FL_PARTIALGROUND ) ! 247: { // entity had floor mostly pulled out from underneath it ! 248: // and is trying to correct ! 249: if (relink) ! 250: { ! 251: gi.linkentity (ent); ! 252: G_TouchTriggers (ent); ! 253: } ! 254: return true; ! 255: } ! 256: VectorCopy (oldorg, ent->s.origin); ! 257: return false; ! 258: } ! 259: ! 260: if ( ent->flags & FL_PARTIALGROUND ) ! 261: { ! 262: ent->flags &= ~FL_PARTIALGROUND; ! 263: } ! 264: ent->groundentity = trace.ent; ! 265: ent->groundentity_linkcount = trace.ent->linkcount; ! 266: ! 267: // the move is ok ! 268: if (relink) ! 269: { ! 270: gi.linkentity (ent); ! 271: G_TouchTriggers (ent); ! 272: } ! 273: return true; ! 274: } ! 275: ! 276: ! 277: //============================================================================ ! 278: ! 279: /* ! 280: =============== ! 281: M_ChangeYaw ! 282: ! 283: =============== ! 284: */ ! 285: void M_ChangeYaw (edict_t *ent) ! 286: { ! 287: float ideal; ! 288: float current; ! 289: float move; ! 290: float speed; ! 291: ! 292: current = anglemod(ent->s.angles[YAW]); ! 293: ideal = ent->ideal_yaw; ! 294: ! 295: if (current == ideal) ! 296: return; ! 297: ! 298: move = ideal - current; ! 299: speed = ent->yaw_speed; ! 300: if (ideal > current) ! 301: { ! 302: if (move >= 180) ! 303: move = move - 360; ! 304: } ! 305: else ! 306: { ! 307: if (move <= -180) ! 308: move = move + 360; ! 309: } ! 310: if (move > 0) ! 311: { ! 312: if (move > speed) ! 313: move = speed; ! 314: } ! 315: else ! 316: { ! 317: if (move < -speed) ! 318: move = -speed; ! 319: } ! 320: ! 321: ent->s.angles[YAW] = anglemod (current + move); ! 322: } ! 323: ! 324: ! 325: /* ! 326: ====================== ! 327: SV_StepDirection ! 328: ! 329: Turns to the movement direction, and walks the current distance if ! 330: facing it. ! 331: ! 332: ====================== ! 333: */ ! 334: qboolean SV_StepDirection (edict_t *ent, float yaw, float dist) ! 335: { ! 336: vec3_t move, oldorigin; ! 337: float delta; ! 338: ! 339: ent->ideal_yaw = yaw; ! 340: M_ChangeYaw (ent); ! 341: ! 342: yaw = yaw*M_PI*2 / 360; ! 343: move[0] = cos(yaw)*dist; ! 344: move[1] = sin(yaw)*dist; ! 345: move[2] = 0; ! 346: ! 347: VectorCopy (ent->s.origin, oldorigin); ! 348: if (SV_movestep (ent, move, false)) ! 349: { ! 350: delta = ent->s.angles[YAW] - ent->ideal_yaw; ! 351: if (delta > 45 && delta < 315) ! 352: { // not turned far enough, so don't take the step ! 353: VectorCopy (oldorigin, ent->s.origin); ! 354: } ! 355: gi.linkentity (ent); ! 356: G_TouchTriggers (ent); ! 357: return true; ! 358: } ! 359: gi.linkentity (ent); ! 360: G_TouchTriggers (ent); ! 361: return false; ! 362: } ! 363: ! 364: /* ! 365: ====================== ! 366: SV_FixCheckBottom ! 367: ! 368: ====================== ! 369: */ ! 370: void SV_FixCheckBottom (edict_t *ent) ! 371: { ! 372: ent->flags |= FL_PARTIALGROUND; ! 373: } ! 374: ! 375: ! 376: ! 377: /* ! 378: ================ ! 379: SV_NewChaseDir ! 380: ! 381: ================ ! 382: */ ! 383: #define DI_NODIR -1 ! 384: void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist) ! 385: { ! 386: float deltax,deltay; ! 387: float d[3]; ! 388: float tdir, olddir, turnaround; ! 389: ! 390: //FIXME: how did we get here with no enemy ! 391: if (!enemy) ! 392: return; ! 393: ! 394: olddir = anglemod( (int)(actor->ideal_yaw/45)*45 ); ! 395: turnaround = anglemod(olddir - 180); ! 396: ! 397: deltax = enemy->s.origin[0] - actor->s.origin[0]; ! 398: deltay = enemy->s.origin[1] - actor->s.origin[1]; ! 399: if (deltax>10) ! 400: d[1]= 0; ! 401: else if (deltax<-10) ! 402: d[1]= 180; ! 403: else ! 404: d[1]= DI_NODIR; ! 405: if (deltay<-10) ! 406: d[2]= 270; ! 407: else if (deltay>10) ! 408: d[2]= 90; ! 409: else ! 410: d[2]= DI_NODIR; ! 411: ! 412: // try direct route ! 413: if (d[1] != DI_NODIR && d[2] != DI_NODIR) ! 414: { ! 415: if (d[1] == 0) ! 416: tdir = d[2] == 90 ? 45 : 315; ! 417: else ! 418: tdir = d[2] == 90 ? 135 : 215; ! 419: ! 420: if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) ! 421: return; ! 422: } ! 423: ! 424: // try other directions ! 425: if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax)) ! 426: { ! 427: tdir=d[1]; ! 428: d[1]=d[2]; ! 429: d[2]=tdir; ! 430: } ! 431: ! 432: if (d[1]!=DI_NODIR && d[1]!=turnaround ! 433: && SV_StepDirection(actor, d[1], dist)) ! 434: return; ! 435: ! 436: if (d[2]!=DI_NODIR && d[2]!=turnaround ! 437: && SV_StepDirection(actor, d[2], dist)) ! 438: return; ! 439: ! 440: /* there is no direct path to the player, so pick another direction */ ! 441: ! 442: if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist)) ! 443: return; ! 444: ! 445: if (rand()&1) /*randomly determine direction of search*/ ! 446: { ! 447: for (tdir=0 ; tdir<=315 ; tdir += 45) ! 448: if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) ! 449: return; ! 450: } ! 451: else ! 452: { ! 453: for (tdir=315 ; tdir >=0 ; tdir -= 45) ! 454: if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) ! 455: return; ! 456: } ! 457: ! 458: if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) ) ! 459: return; ! 460: ! 461: actor->ideal_yaw = olddir; // can't move ! 462: ! 463: // if a bridge was pulled out from underneath a monster, it may not have ! 464: // a valid standing position at all ! 465: ! 466: if (!M_CheckBottom (actor)) ! 467: SV_FixCheckBottom (actor); ! 468: } ! 469: ! 470: /* ! 471: ====================== ! 472: SV_CloseEnough ! 473: ! 474: ====================== ! 475: */ ! 476: qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist) ! 477: { ! 478: int i; ! 479: ! 480: for (i=0 ; i<3 ; i++) ! 481: { ! 482: if (goal->absmin[i] > ent->absmax[i] + dist) ! 483: return false; ! 484: if (goal->absmax[i] < ent->absmin[i] - dist) ! 485: return false; ! 486: } ! 487: return true; ! 488: } ! 489: ! 490: ! 491: /* ! 492: ====================== ! 493: M_MoveToGoal ! 494: ====================== ! 495: */ ! 496: void M_MoveToGoal (edict_t *ent, float dist) ! 497: { ! 498: edict_t *goal; ! 499: ! 500: goal = ent->goalentity; ! 501: ! 502: if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM))) ! 503: return; ! 504: ! 505: // if the next step hits the enemy, return immediately ! 506: if (ent->enemy && SV_CloseEnough (ent, ent->enemy, dist) ) ! 507: return; ! 508: ! 509: // bump around... ! 510: if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->ideal_yaw, dist)) ! 511: { ! 512: if (ent->inuse) ! 513: SV_NewChaseDir (ent, goal, dist); ! 514: } ! 515: } ! 516: ! 517: ! 518: /* ! 519: =============== ! 520: M_walkmove ! 521: =============== ! 522: */ ! 523: qboolean M_walkmove (edict_t *ent, float yaw, float dist) ! 524: { ! 525: vec3_t move; ! 526: ! 527: if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM))) ! 528: return false; ! 529: ! 530: yaw = yaw*M_PI*2 / 360; ! 531: ! 532: move[0] = cos(yaw)*dist; ! 533: move[1] = sin(yaw)*dist; ! 534: move[2] = 0; ! 535: ! 536: return SV_movestep(ent, move, true); ! 537: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.