1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19*/ 20// sv_move.c -- monster movement 21 22#include "qwsvdef.h" 23 24#define STEPSIZE 18 25 26/* 27============= 28SV_CheckBottom 29 30Returns false if any part of the bottom of the entity is off an edge that 31is not a staircase. 32 33============= 34*/ 35int c_yes, c_no; 36 37qboolean 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->v.origin, ent->v.mins, mins); 45 VectorAdd (ent->v.origin, ent->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 63realcheck: 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============= 102SV_movestep 103 104Called by monster program code. 105The move will be adjusted for slopes and stairs, but if the move isn't 106possible, no move is done, false is returned, and 107pr_global_struct->trace_normal is set to the normal of the blocking wall 108============= 109*/ 110qboolean 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->v.origin, oldorg); 120 VectorAdd (ent->v.origin, move, neworg); 121 122// flying monsters don't step up 123 if ( (int)ent->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->v.origin, move, neworg); 129 enemy = PROG_TO_EDICT(ent->v.enemy); 130 if (i == 0 && enemy != sv.edicts) 131 { 132 dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->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->v.origin, ent->v.mins, ent->v.maxs, neworg, false, ent); 139 140 if (trace.fraction == 1) 141 { 142 if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY ) 143 return false; // swim monster left water 144 145 VectorCopy (trace.endpos, ent->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->v.mins, ent->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->v.mins, ent->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->v.flags & FL_PARTIALGROUND ) 179 { 180 VectorAdd (ent->v.origin, move, ent->v.origin); 181 if (relink) 182 SV_LinkEdict (ent, true); 183 ent->v.flags = (int)ent->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->v.origin); 193 194 if (!SV_CheckBottom (ent)) 195 { 196 if ( (int)ent->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->v.origin); 204 return false; 205 } 206 207 if ( (int)ent->v.flags & FL_PARTIALGROUND ) 208 { 209// Con_Printf ("back on ground\n"); 210 ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND; 211 } 212 ent->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====================== 225SV_StepDirection 226 227Turns to the movement direction, and walks the current distance if 228facing it. 229 230====================== 231*/ 232void PF_changeyaw (void); 233qboolean SV_StepDirection (edict_t *ent, float yaw, float dist) 234{ 235 vec3_t move, oldorigin; 236 float delta; 237 238 ent->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->v.origin, oldorigin); 247 if (SV_movestep (ent, move, false)) 248 { 249 delta = ent->v.angles[YAW] - ent->v.ideal_yaw; 250 if (delta > 45 && delta < 315) 251 { // not turned far enough, so don't take the step 252 VectorCopy (oldorigin, ent->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====================== 264SV_FixCheckBottom 265 266====================== 267*/ 268void SV_FixCheckBottom (edict_t *ent) 269{ 270// Con_Printf ("SV_FixCheckBottom\n"); 271 272 ent->v.flags = (int)ent->v.flags | FL_PARTIALGROUND; 273} 274 275 276 277/* 278================ 279SV_NewChaseDir 280 281================ 282*/ 283#define DI_NODIR -1 284void 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->v.ideal_yaw/45)*45 ); 291 turnaround = anglemod(olddir - 180); 292 293 deltax = enemy->v.origin[0] - actor->v.origin[0]; 294 deltay = enemy->v.origin[1] - actor->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(deltay)>abs(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->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====================== 369SV_CloseEnough 370 371====================== 372*/ 373qboolean 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->v.absmin[i] > ent->v.absmax[i] + dist) 380 return false; 381 if (goal->v.absmax[i] < ent->v.absmin[i] - dist) 382 return false; 383 } 384 return true; 385} 386 387/* 388====================== 389SV_MoveToGoal 390 391====================== 392*/ 393void SV_MoveToGoal (void) 394{ 395 edict_t *ent, *goal; 396 float dist; 397 398 ent = PROG_TO_EDICT(pr_global_struct->self); 399 goal = PROG_TO_EDICT(ent->v.goalentity); 400 dist = G_FLOAT(OFS_PARM0); 401 402 if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) ) 403 { 404 G_FLOAT(OFS_RETURN) = 0; 405 return; 406 } 407 408// if the next step hits the enemy, return immediately 409 if ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) ) 410 return; 411 412// bump around... 413 if ( (rand()&3)==1 || 414 !SV_StepDirection (ent, ent->v.ideal_yaw, dist)) 415 { 416 SV_NewChaseDir (ent, goal, dist); 417 } 418} 419 420