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
30 Returns false if any part of the bottom of the entity is off an edge that
37 qboolean SV_CheckBottom (edict_t *ent)
39 vec3_t mins, maxs, start, stop;
44 VectorAdd (ent->v.origin, ent->v.mins, mins);
45 VectorAdd (ent->v.origin, ent->v.maxs, maxs);
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++)
54 start[0] = x ? maxs[0] : mins[0];
55 start[1] = y ? maxs[1] : mins[1];
56 if (SV_PointContents (start) != CONTENTS_SOLID)
61 return true; // we got out easy
66 // check it for real...
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, MOVE_NOMONSTERS, ent);
76 if (trace.fraction == 1.0)
78 mid = bottom = trace.endpos[2];
80 // the corners must be within 16 of the midpoint
81 for (x=0 ; x<=1 ; x++)
82 for (y=0 ; y<=1 ; y++)
84 start[0] = stop[0] = x ? maxs[0] : mins[0];
85 start[1] = stop[1] = y ? maxs[1] : mins[1];
87 trace = SV_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent);
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)
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
110 qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
113 vec3_t oldorg, neworg, end, traceendpos;
119 VectorCopy (ent->v.origin, oldorg);
120 VectorAdd (ent->v.origin, move, neworg);
122 // flying monsters don't step up
123 if ( (int)ent->v.flags & (FL_SWIM | FL_FLY) )
125 // try one move with vertical motion, then one without
126 for (i=0 ; i<2 ; i++)
128 VectorAdd (ent->v.origin, move, neworg);
129 enemy = PROG_TO_EDICT(ent->v.enemy);
130 if (i == 0 && enemy != sv.edicts)
132 dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2];
138 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, MOVE_NORMAL, ent);
140 if (trace.fraction == 1)
142 VectorCopy(trace.endpos, traceendpos);
143 if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(traceendpos) == CONTENTS_EMPTY )
144 return false; // swim monster left water
146 VectorCopy (traceendpos, ent->v.origin);
148 SV_LinkEdict (ent, true);
152 if (enemy == sv.edicts)
159 // push down from a step height above the wished position
160 neworg[2] += STEPSIZE;
161 VectorCopy (neworg, end);
162 end[2] -= STEPSIZE*2;
164 trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
169 if (trace.startsolid)
171 neworg[2] -= STEPSIZE;
172 trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
173 if (trace.allsolid || trace.startsolid)
176 if (trace.fraction == 1)
178 // if monster had the ground pulled out, go ahead and fall
179 if ( (int)ent->v.flags & FL_PARTIALGROUND )
181 VectorAdd (ent->v.origin, move, ent->v.origin);
183 SV_LinkEdict (ent, true);
184 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
185 // Con_Printf ("fall down\n");
189 return false; // walked off an edge
192 // check point traces down for dangling corners
193 VectorCopy (trace.endpos, ent->v.origin);
195 if (!SV_CheckBottom (ent))
197 if ( (int)ent->v.flags & FL_PARTIALGROUND )
198 { // entity had floor mostly pulled out from underneath it
199 // and is trying to correct
201 SV_LinkEdict (ent, true);
204 VectorCopy (oldorg, ent->v.origin);
208 if ( (int)ent->v.flags & FL_PARTIALGROUND )
210 // Con_Printf ("back on ground\n");
211 ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND;
213 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
217 SV_LinkEdict (ent, true);
222 //============================================================================
225 ======================
228 Turns to the movement direction, and walks the current distance if
231 ======================
233 void PF_changeyaw (void);
234 qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
236 vec3_t move, oldorigin;
239 ent->v.ideal_yaw = yaw;
242 yaw = yaw*M_PI*2 / 360;
243 move[0] = cos(yaw)*dist;
244 move[1] = sin(yaw)*dist;
247 VectorCopy (ent->v.origin, oldorigin);
248 if (SV_movestep (ent, move, false))
250 delta = ent->v.angles[YAW] - ent->v.ideal_yaw;
251 if (delta > 45 && delta < 315)
252 { // not turned far enough, so don't take the step
253 VectorCopy (oldorigin, ent->v.origin);
255 SV_LinkEdict (ent, true);
258 SV_LinkEdict (ent, true);
264 ======================
267 ======================
269 void SV_FixCheckBottom (edict_t *ent)
271 // Con_Printf ("SV_FixCheckBottom\n");
273 ent->v.flags = (int)ent->v.flags | FL_PARTIALGROUND;
285 void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
289 float tdir, olddir, turnaround;
291 olddir = ANGLEMOD((int)(actor->v.ideal_yaw/45)*45);
292 turnaround = ANGLEMOD(olddir - 180);
294 deltax = enemy->v.origin[0] - actor->v.origin[0];
295 deltay = enemy->v.origin[1] - actor->v.origin[1];
310 if (d[1] != DI_NODIR && d[2] != DI_NODIR)
313 tdir = d[2] == 90 ? 45 : 315;
315 tdir = d[2] == 90 ? 135 : 215;
317 if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
321 // try other directions
322 if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax))
329 if (d[1]!=DI_NODIR && d[1]!=turnaround
330 && SV_StepDirection(actor, d[1], dist))
333 if (d[2]!=DI_NODIR && d[2]!=turnaround
334 && SV_StepDirection(actor, d[2], dist))
337 /* there is no direct path to the player, so pick another direction */
339 if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
342 if (rand()&1) /*randomly determine direction of search*/
344 for (tdir=0 ; tdir<=315 ; tdir += 45)
345 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
350 for (tdir=315 ; tdir >=0 ; tdir -= 45)
351 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
355 if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
358 actor->v.ideal_yaw = olddir; // can't move
360 // if a bridge was pulled out from underneath a monster, it may not have
361 // a valid standing position at all
363 if (!SV_CheckBottom (actor))
364 SV_FixCheckBottom (actor);
369 ======================
372 ======================
374 qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
378 for (i=0 ; i<3 ; i++)
380 if (goal->v.absmin[i] > ent->v.absmax[i] + dist)
382 if (goal->v.absmax[i] < ent->v.absmin[i] - dist)
389 ======================
392 ======================
394 void SV_MoveToGoal (void)
399 ent = PROG_TO_EDICT(pr_global_struct->self);
400 goal = PROG_TO_EDICT(ent->v.goalentity);
401 dist = G_FLOAT(OFS_PARM0);
403 if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
405 G_FLOAT(OFS_RETURN) = 0;
409 // if the next step hits the enemy, return immediately
410 if ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) )
414 if ( (rand()&3)==1 ||
415 !SV_StepDirection (ent, ent->v.ideal_yaw, dist))
417 SV_NewChaseDir (ent, goal, dist);