1 /* 2 Copyright (C) 1996-1997 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 */ 20 // sv_move.c -- monster movement 21 22 #include "quakedef.h" 23 24 #define STEPSIZE 18 25 26 /* 27 ============= 28 SV_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 SV_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->u.v.origin, ent->u.v.mins, mins); 45 VectorAdd (ent->u.v.origin, ent->u.v.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 (SV_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 = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent); 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 = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent); 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 qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink) 111 { 112 float dz; 113 vec3_t oldorg, neworg, end; 114 trace_t trace; 115 int i; 116 edict_t *enemy; 117 118 // try the move 119 VectorCopy (ent->u.v.origin, oldorg); 120 VectorAdd (ent->u.v.origin, move, neworg); 121 122 // flying monsters don't step up 123 if ( (int)ent->u.v.flags & (FL_SWIM | FL_FLY) ) 124 { 125 // try one move with vertical motion, then one without 126 for (i=0 ; i<2 ; i++) 127 { 128 VectorAdd (ent->u.v.origin, move, neworg); 129 enemy = PROG_TO_EDICT(ent->u.v.enemy); 130 if (i == 0 && enemy != sv.edicts) 131 { 132 dz = ent->u.v.origin[2] - PROG_TO_EDICT(ent->u.v.enemy)->u.v.origin[2]; 133 if (dz > 40) 134 neworg[2] -= 8; 135 if (dz < 30) 136 neworg[2] += 8; 137 } 138 trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, neworg, false, ent); 139 140 if (trace.fraction == 1) 141 { 142 if ( ((int)ent->u.v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY ) 143 return false; // swim monster left water 144 145 VectorCopy (trace.endpos, ent->u.v.origin); 146 if (relink) 147 SV_LinkEdict (ent, true); 148 return true; 149 } 150 151 if (enemy == sv.edicts) 152 break; 153 } 154 155 return false; 156 } 157 158 // push down from a step height above the wished position 159 neworg[2] += STEPSIZE; 160 VectorCopy (neworg, end); 161 end[2] -= STEPSIZE*2; 162 163 trace = SV_Move (neworg, ent->u.v.mins, ent->u.v.maxs, end, false, ent); 164 165 if (trace.allsolid) 166 return false; 167 168 if (trace.startsolid) 169 { 170 neworg[2] -= STEPSIZE; 171 trace = SV_Move (neworg, ent->u.v.mins, ent->u.v.maxs, end, false, ent); 172 if (trace.allsolid || trace.startsolid) 173 return false; 174 } 175 if (trace.fraction == 1) 176 { 177 // if monster had the ground pulled out, go ahead and fall 178 if ( (int)ent->u.v.flags & FL_PARTIALGROUND ) 179 { 180 VectorAdd (ent->u.v.origin, move, ent->u.v.origin); 181 if (relink) 182 SV_LinkEdict (ent, true); 183 ent->u.v.flags = (int)ent->u.v.flags & ~FL_ONGROUND; 184 // Con_Printf ("fall down\n"); 185 return true; 186 } 187 188 return false; // walked off an edge 189 } 190 191 // check point traces down for dangling corners 192 VectorCopy (trace.endpos, ent->u.v.origin); 193 194 if (!SV_CheckBottom (ent)) 195 { 196 if ( (int)ent->u.v.flags & FL_PARTIALGROUND ) 197 { // entity had floor mostly pulled out from underneath it 198 // and is trying to correct 199 if (relink) 200 SV_LinkEdict (ent, true); 201 return true; 202 } 203 VectorCopy (oldorg, ent->u.v.origin); 204 return false; 205 } 206 207 if ( (int)ent->u.v.flags & FL_PARTIALGROUND ) 208 { 209 // Con_Printf ("back on ground\n"); 210 ent->u.v.flags = (int)ent->u.v.flags & ~FL_PARTIALGROUND; 211 } 212 ent->u.v.groundentity = EDICT_TO_PROG(trace.ent); 213 214 // the move is ok 215 if (relink) 216 SV_LinkEdict (ent, true); 217 return true; 218 } 219 220 221 //============================================================================ 222 223 /* 224 ====================== 225 SV_StepDirection 226 227 Turns to the movement direction, and walks the current distance if 228 facing it. 229 230 ====================== 231 */ 232 void PF_changeyaw (void); 233 qboolean SV_StepDirection (edict_t *ent, float yaw, float dist) 234 { 235 vec3_t move, oldorigin; 236 float delta; 237 238 ent->u.v.ideal_yaw = yaw; 239 PF_changeyaw(); 240 241 yaw = yaw*M_PI*2 / 360; 242 move[0] = cos(yaw)*dist; 243 move[1] = sin(yaw)*dist; 244 move[2] = 0; 245 246 VectorCopy (ent->u.v.origin, oldorigin); 247 if (SV_movestep (ent, move, false)) 248 { 249 delta = ent->u.v.angles[YAW] - ent->u.v.ideal_yaw; 250 if (delta > 45 && delta < 315) 251 { // not turned far enough, so don't take the step 252 VectorCopy (oldorigin, ent->u.v.origin); 253 } 254 SV_LinkEdict (ent, true); 255 return true; 256 } 257 SV_LinkEdict (ent, true); 258 259 return false; 260 } 261 262 /* 263 ====================== 264 SV_FixCheckBottom 265 266 ====================== 267 */ 268 void SV_FixCheckBottom (edict_t *ent) 269 { 270 // Con_Printf ("SV_FixCheckBottom\n"); 271 272 ent->u.v.flags = (int)ent->u.v.flags | FL_PARTIALGROUND; 273 } 274 275 276 277 /* 278 ================ 279 SV_NewChaseDir 280 281 ================ 282 */ 283 #define DI_NODIR -1 284 void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist) 285 { 286 float deltax,deltay; 287 float d[3]; 288 float tdir, olddir, turnaround; 289 290 olddir = anglemod( (int)(actor->u.v.ideal_yaw/45)*45 ); 291 turnaround = anglemod(olddir - 180); 292 293 deltax = enemy->u.v.origin[0] - actor->u.v.origin[0]; 294 deltay = enemy->u.v.origin[1] - actor->u.v.origin[1]; 295 if (deltax>10) 296 d[1]= 0; 297 else if (deltax<-10) 298 d[1]= 180; 299 else 300 d[1]= DI_NODIR; 301 if (deltay<-10) 302 d[2]= 270; 303 else if (deltay>10) 304 d[2]= 90; 305 else 306 d[2]= DI_NODIR; 307 308 // try direct route 309 if (d[1] != DI_NODIR && d[2] != DI_NODIR) 310 { 311 if (d[1] == 0) 312 tdir = d[2] == 90 ? 45 : 315; 313 else 314 tdir = d[2] == 90 ? 135 : 215; 315 316 if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) 317 return; 318 } 319 320 // try other directions 321 if ( ((rand()&3) & 1) || abs((int) deltay)>abs((int) deltax)) 322 { 323 tdir=d[1]; 324 d[1]=d[2]; 325 d[2]=tdir; 326 } 327 328 if (d[1]!=DI_NODIR && d[1]!=turnaround 329 && SV_StepDirection(actor, d[1], dist)) 330 return; 331 332 if (d[2]!=DI_NODIR && d[2]!=turnaround 333 && SV_StepDirection(actor, d[2], dist)) 334 return; 335 336 /* there is no direct path to the player, so pick another direction */ 337 338 if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist)) 339 return; 340 341 if (rand()&1) /*randomly determine direction of search*/ 342 { 343 for (tdir=0 ; tdir<=315 ; tdir += 45) 344 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) 345 return; 346 } 347 else 348 { 349 for (tdir=315 ; tdir >=0 ; tdir -= 45) 350 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) 351 return; 352 } 353 354 if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) ) 355 return; 356 357 actor->u.v.ideal_yaw = olddir; // can't move 358 359 // if a bridge was pulled out from underneath a monster, it may not have 360 // a valid standing position at all 361 362 if (!SV_CheckBottom (actor)) 363 SV_FixCheckBottom (actor); 364 365 } 366 367 /* 368 ====================== 369 SV_CloseEnough 370 371 ====================== 372 */ 373 qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist) 374 { 375 int i; 376 377 for (i=0 ; i<3 ; i++) 378 { 379 if (goal->u.v.absmin[i] > ent->u.v.absmax[i] + dist) 380 return false; 381 if (goal->u.v.absmax[i] < ent->u.v.absmin[i] - dist) 382 return false; 383 } 384 return true; 385 } 386 387 /* 388 ====================== 389 SV_MoveToGoal 390 391 ====================== 392 */ 393 void SV_MoveToGoal (void) 394 { 395 edict_t *ent, *goal; 396 float dist; 397 #ifdef QUAKE2 398 edict_t *enemy; 399 #endif 400 401 ent = PROG_TO_EDICT(pr_global_struct->self); 402 goal = PROG_TO_EDICT(ent->u.v.goalentity); 403 dist = G_FLOAT(OFS_PARM0); 404 405 if ( !( (int)ent->u.v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) ) 406 { 407 G_FLOAT(OFS_RETURN) = 0; 408 return; 409 } 410 411 // if the next step hits the enemy, return immediately 412 #ifdef QUAKE2 413 enemy = PROG_TO_EDICT(ent->u.v.enemy); 414 if (enemy != sv.edicts && SV_CloseEnough (ent, enemy, dist) ) 415 #else 416 if ( PROG_TO_EDICT(ent->u.v.enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) ) 417 #endif 418 return; 419 420 // bump around... 421 if ( (rand()&3)==1 || 422 !SV_StepDirection (ent, ent->u.v.ideal_yaw, dist)) 423 { 424 SV_NewChaseDir (ent, goal, dist); 425 } 426 } 427 428