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
23 #include "prvm_cmds.h"
29 Returns false if any part of the bottom of the entity is off an edge that
36 qboolean SV_CheckBottom (prvm_edict_t *ent)
38 vec3_t mins, maxs, start, stop;
43 VectorAdd (ent->fields.server->origin, ent->fields.server->mins, mins);
44 VectorAdd (ent->fields.server->origin, ent->fields.server->maxs, maxs);
46 // if all of the points under the corners are solid world, don't bother
47 // with the tougher checks
48 // the corners must be within 16 of the midpoint
49 start[2] = mins[2] - 1;
50 for (x=0 ; x<=1 ; x++)
51 for (y=0 ; y<=1 ; y++)
53 start[0] = x ? maxs[0] : mins[0];
54 start[1] = y ? maxs[1] : mins[1];
55 if (!(SV_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
60 return true; // we got out easy
65 // check it for real...
69 // the midpoint must be within 16 of the bottom
70 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
71 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
72 stop[2] = start[2] - 2*sv_stepheight.value;
73 trace = SV_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
75 if (trace.fraction == 1.0)
77 mid = bottom = trace.endpos[2];
79 // the corners must be within 16 of the midpoint
80 for (x=0 ; x<=1 ; x++)
81 for (y=0 ; y<=1 ; y++)
83 start[0] = stop[0] = x ? maxs[0] : mins[0];
84 start[1] = stop[1] = y ? maxs[1] : mins[1];
86 trace = SV_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
88 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
89 bottom = trace.endpos[2];
90 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
103 Called by monster program code.
104 The move will be adjusted for slopes and stairs, but if the move isn't
105 possible, no move is done and false is returned
108 qboolean SV_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
111 vec3_t oldorg, neworg, end, traceendpos;
117 VectorCopy (ent->fields.server->origin, oldorg);
118 VectorAdd (ent->fields.server->origin, move, neworg);
120 // flying monsters don't step up
121 if ( (int)ent->fields.server->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->fields.server->origin, move, neworg);
128 enemy = prog->edicts;
131 enemy = PRVM_PROG_TO_EDICT(ent->fields.server->enemy);
132 if (i == 0 && enemy != prog->edicts)
134 dz = ent->fields.server->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.server->enemy)->fields.server->origin[2];
141 trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, neworg, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
143 if (trace.fraction == 1)
145 VectorCopy(trace.endpos, traceendpos);
146 if (((int)ent->fields.server->flags & FL_SWIM) && !(SV_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
147 return false; // swim monster left water
149 VectorCopy (traceendpos, ent->fields.server->origin);
151 SV_LinkEdict (ent, true);
155 if (enemy == prog->edicts)
162 // push down from a step height above the wished position
163 neworg[2] += sv_stepheight.value;
164 VectorCopy (neworg, end);
165 end[2] -= sv_stepheight.value*2;
167 trace = SV_Move (neworg, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
169 if (trace.startsolid)
171 neworg[2] -= sv_stepheight.value;
172 trace = SV_Move (neworg, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
173 if (trace.startsolid)
176 if (trace.fraction == 1)
178 // if monster had the ground pulled out, go ahead and fall
179 if ( (int)ent->fields.server->flags & FL_PARTIALGROUND )
181 VectorAdd (ent->fields.server->origin, move, ent->fields.server->origin);
183 SV_LinkEdict (ent, true);
184 ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND;
188 return false; // walked off an edge
191 // check point traces down for dangling corners
192 VectorCopy (trace.endpos, ent->fields.server->origin);
194 if (!SV_CheckBottom (ent))
196 if ( (int)ent->fields.server->flags & FL_PARTIALGROUND )
197 { // entity had floor mostly pulled out from underneath it
198 // and is trying to correct
200 SV_LinkEdict (ent, true);
203 VectorCopy (oldorg, ent->fields.server->origin);
207 if ( (int)ent->fields.server->flags & FL_PARTIALGROUND )
208 ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_PARTIALGROUND;
210 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
214 SV_LinkEdict (ent, true);
219 //============================================================================
222 ======================
225 Turns to the movement direction, and walks the current distance if
228 ======================
230 void VM_changeyaw (void);
231 qboolean SV_StepDirection (prvm_edict_t *ent, float yaw, float dist)
233 vec3_t move, oldorigin;
236 ent->fields.server->ideal_yaw = yaw;
239 yaw = yaw*M_PI*2 / 360;
240 move[0] = cos(yaw)*dist;
241 move[1] = sin(yaw)*dist;
244 VectorCopy (ent->fields.server->origin, oldorigin);
245 if (SV_movestep (ent, move, false, false, false))
247 delta = ent->fields.server->angles[YAW] - ent->fields.server->ideal_yaw;
248 if (delta > 45 && delta < 315)
249 { // not turned far enough, so don't take the step
250 VectorCopy (oldorigin, ent->fields.server->origin);
252 SV_LinkEdict (ent, true);
255 SV_LinkEdict (ent, true);
261 ======================
264 ======================
266 void SV_FixCheckBottom (prvm_edict_t *ent)
268 ent->fields.server->flags = (int)ent->fields.server->flags | FL_PARTIALGROUND;
280 void SV_NewChaseDir (prvm_edict_t *actor, prvm_edict_t *enemy, float dist)
284 float tdir, olddir, turnaround;
286 olddir = ANGLEMOD((int)(actor->fields.server->ideal_yaw/45)*45);
287 turnaround = ANGLEMOD(olddir - 180);
289 deltax = enemy->fields.server->origin[0] - actor->fields.server->origin[0];
290 deltay = enemy->fields.server->origin[1] - actor->fields.server->origin[1];
305 if (d[1] != DI_NODIR && d[2] != DI_NODIR)
308 tdir = d[2] == 90 ? 45 : 315;
310 tdir = d[2] == 90 ? 135 : 215;
312 if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
316 // try other directions
317 if ( ((rand()&3) & 1) || fabs(deltay)>fabs(deltax))
324 if (d[1]!=DI_NODIR && d[1]!=turnaround
325 && SV_StepDirection(actor, d[1], dist))
328 if (d[2]!=DI_NODIR && d[2]!=turnaround
329 && SV_StepDirection(actor, d[2], dist))
332 /* there is no direct path to the player, so pick another direction */
334 if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
337 if (rand()&1) /*randomly determine direction of search*/
339 for (tdir=0 ; tdir<=315 ; tdir += 45)
340 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
345 for (tdir=315 ; tdir >=0 ; tdir -= 45)
346 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
350 if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
353 actor->fields.server->ideal_yaw = olddir; // can't move
355 // if a bridge was pulled out from underneath a monster, it may not have
356 // a valid standing position at all
358 if (!SV_CheckBottom (actor))
359 SV_FixCheckBottom (actor);
364 ======================
367 ======================
369 qboolean SV_CloseEnough (prvm_edict_t *ent, prvm_edict_t *goal, float dist)
373 for (i=0 ; i<3 ; i++)
375 if (goal->priv.server->areamins[i] > ent->priv.server->areamaxs[i] + dist)
377 if (goal->priv.server->areamaxs[i] < ent->priv.server->areamins[i] - dist)
384 ======================
387 ======================
389 void SV_MoveToGoal (void)
391 prvm_edict_t *ent, *goal;
394 VM_SAFEPARMCOUNT(1, SV_MoveToGoal);
396 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
397 goal = PRVM_PROG_TO_EDICT(ent->fields.server->goalentity);
398 dist = PRVM_G_FLOAT(OFS_PARM0);
400 if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
402 PRVM_G_FLOAT(OFS_RETURN) = 0;
406 // if the next step hits the enemy, return immediately
407 if ( PRVM_PROG_TO_EDICT(ent->fields.server->enemy) != prog->edicts && SV_CloseEnough (ent, goal, dist) )
411 if ( (rand()&3)==1 ||
412 !SV_StepDirection (ent, ent->fields.server->ideal_yaw, dist))
414 SV_NewChaseDir (ent, goal, dist);