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