2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // sv_move.c -- monster movement
28 Returns false if any part of the bottom of the entity is off an edge that
35 qboolean SV_CheckBottom (edict_t *ent)
37 vec3_t mins, maxs, start, stop;
42 VectorAdd (ent->v.origin, ent->v.mins, mins);
43 VectorAdd (ent->v.origin, ent->v.maxs, maxs);
45 // if all of the points under the corners are solid world, don't bother
46 // with the tougher checks
47 // the corners must be within 16 of the midpoint
48 start[2] = mins[2] - 1;
49 for (x=0 ; x<=1 ; x++)
50 for (y=0 ; y<=1 ; y++)
52 start[0] = x ? maxs[0] : mins[0];
53 start[1] = y ? maxs[1] : mins[1];
54 if (Mod_PointInLeaf(start, sv.worldmodel)->contents != CONTENTS_SOLID)
59 return true; // we got out easy
64 // check it for real...
68 // the midpoint must be within 16 of the bottom
69 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
70 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
71 stop[2] = start[2] - 2*sv_stepheight.value;
72 trace = SV_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent);
74 if (trace.fraction == 1.0)
76 mid = bottom = trace.endpos[2];
78 // the corners must be within 16 of the midpoint
79 for (x=0 ; x<=1 ; x++)
80 for (y=0 ; y<=1 ; y++)
82 start[0] = stop[0] = x ? maxs[0] : mins[0];
83 start[1] = stop[1] = y ? maxs[1] : mins[1];
85 trace = SV_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent);
87 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
88 bottom = trace.endpos[2];
89 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
102 Called by monster program code.
103 The move will be adjusted for slopes and stairs, but if the move isn't
104 possible, no move is done, false is returned, and
105 pr_global_struct->trace_normal is set to the normal of the blocking wall
108 qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
111 vec3_t oldorg, neworg, end, traceendpos;
117 VectorCopy (ent->v.origin, oldorg);
118 VectorAdd (ent->v.origin, move, neworg);
120 // flying monsters don't step up
121 if ( (int)ent->v.flags & (FL_SWIM | FL_FLY) )
123 // try one move with vertical motion, then one without
124 for (i=0 ; i<2 ; i++)
126 VectorAdd (ent->v.origin, move, neworg);
127 enemy = PROG_TO_EDICT(ent->v.enemy);
128 if (i == 0 && enemy != sv.edicts)
130 dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2];
136 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, MOVE_NORMAL, ent);
138 if (trace.fraction == 1)
140 VectorCopy(trace.endpos, traceendpos);
141 if ( ((int)ent->v.flags & FL_SWIM) && Mod_PointInLeaf(traceendpos, sv.worldmodel)->contents == CONTENTS_EMPTY )
142 return false; // swim monster left water
144 VectorCopy (traceendpos, ent->v.origin);
146 SV_LinkEdict (ent, true);
150 if (enemy == sv.edicts)
157 // push down from a step height above the wished position
158 neworg[2] += sv_stepheight.value;
159 VectorCopy (neworg, end);
160 end[2] -= sv_stepheight.value*2;
162 trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
167 if (trace.startsolid)
169 neworg[2] -= sv_stepheight.value;
170 trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
171 if (trace.allsolid || trace.startsolid)
174 if (trace.fraction == 1)
176 // if monster had the ground pulled out, go ahead and fall
177 if ( (int)ent->v.flags & FL_PARTIALGROUND )
179 VectorAdd (ent->v.origin, move, ent->v.origin);
181 SV_LinkEdict (ent, true);
182 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
186 return false; // walked off an edge
189 // check point traces down for dangling corners
190 VectorCopy (trace.endpos, ent->v.origin);
192 if (!SV_CheckBottom (ent))
194 if ( (int)ent->v.flags & FL_PARTIALGROUND )
195 { // entity had floor mostly pulled out from underneath it
196 // and is trying to correct
198 SV_LinkEdict (ent, true);
201 VectorCopy (oldorg, ent->v.origin);
205 if ( (int)ent->v.flags & FL_PARTIALGROUND )
206 ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND;
208 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
212 SV_LinkEdict (ent, true);
217 //============================================================================
220 ======================
223 Turns to the movement direction, and walks the current distance if
226 ======================
228 void PF_changeyaw (void);
229 qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
231 vec3_t move, oldorigin;
234 ent->v.ideal_yaw = yaw;
237 yaw = yaw*M_PI*2 / 360;
238 move[0] = cos(yaw)*dist;
239 move[1] = sin(yaw)*dist;
242 VectorCopy (ent->v.origin, oldorigin);
243 if (SV_movestep (ent, move, false))
245 delta = ent->v.angles[YAW] - ent->v.ideal_yaw;
246 if (delta > 45 && delta < 315)
247 { // not turned far enough, so don't take the step
248 VectorCopy (oldorigin, ent->v.origin);
250 SV_LinkEdict (ent, true);
253 SV_LinkEdict (ent, true);
259 ======================
262 ======================
264 void SV_FixCheckBottom (edict_t *ent)
266 ent->v.flags = (int)ent->v.flags | FL_PARTIALGROUND;
278 void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
282 float tdir, olddir, turnaround;
284 olddir = ANGLEMOD((int)(actor->v.ideal_yaw/45)*45);
285 turnaround = ANGLEMOD(olddir - 180);
287 deltax = enemy->v.origin[0] - actor->v.origin[0];
288 deltay = enemy->v.origin[1] - actor->v.origin[1];
303 if (d[1] != DI_NODIR && d[2] != DI_NODIR)
306 tdir = d[2] == 90 ? 45 : 315;
308 tdir = d[2] == 90 ? 135 : 215;
310 if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
314 // try other directions
315 if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax))
322 if (d[1]!=DI_NODIR && d[1]!=turnaround
323 && SV_StepDirection(actor, d[1], dist))
326 if (d[2]!=DI_NODIR && d[2]!=turnaround
327 && SV_StepDirection(actor, d[2], dist))
330 /* there is no direct path to the player, so pick another direction */
332 if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
335 if (rand()&1) /*randomly determine direction of search*/
337 for (tdir=0 ; tdir<=315 ; tdir += 45)
338 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
343 for (tdir=315 ; tdir >=0 ; tdir -= 45)
344 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
348 if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
351 actor->v.ideal_yaw = olddir; // can't move
353 // if a bridge was pulled out from underneath a monster, it may not have
354 // a valid standing position at all
356 if (!SV_CheckBottom (actor))
357 SV_FixCheckBottom (actor);
362 ======================
365 ======================
367 qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
371 for (i=0 ; i<3 ; i++)
373 if (goal->v.absmin[i] > ent->v.absmax[i] + dist)
375 if (goal->v.absmax[i] < ent->v.absmin[i] - dist)
382 ======================
385 ======================
387 void SV_MoveToGoal (void)
392 ent = PROG_TO_EDICT(pr_global_struct->self);
393 goal = PROG_TO_EDICT(ent->v.goalentity);
394 dist = G_FLOAT(OFS_PARM0);
396 if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
398 G_FLOAT(OFS_RETURN) = 0;
402 // if the next step hits the enemy, return immediately
403 if ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) )
407 if ( (rand()&3)==1 ||
408 !SV_StepDirection (ent, ent->v.ideal_yaw, dist))
410 SV_NewChaseDir (ent, goal, dist);