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 prvm_prog_t *prog = SVVM_prog;
39 vec3_t mins, maxs, start, stop;
44 VectorAdd (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
45 VectorAdd (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, 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_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
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*sv_stepheight.value;
74 trace = SV_TraceLine(start, stop, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(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_TraceLine(start, stop, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(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] > sv_stepheight.value)
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 and false is returned
109 qboolean SV_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
111 prvm_prog_t *prog = SVVM_prog;
113 vec3_t oldorg, neworg, end, traceendpos;
119 VectorCopy (PRVM_serveredictvector(ent, origin), oldorg);
120 VectorAdd (PRVM_serveredictvector(ent, origin), move, neworg);
122 // flying monsters don't step up
123 if ( (int)PRVM_serveredictfloat(ent, flags) & (FL_SWIM | FL_FLY) )
125 // try one move with vertical motion, then one without
126 for (i=0 ; i<2 ; i++)
128 VectorAdd (PRVM_serveredictvector(ent, origin), move, neworg);
130 enemy = prog->edicts;
133 enemy = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, enemy));
134 if (i == 0 && enemy != prog->edicts)
136 dz = PRVM_serveredictvector(ent, origin)[2] - PRVM_serveredictvector(enemy, origin)[2];
143 trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), neworg, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
145 if (trace.fraction == 1)
147 VectorCopy(trace.endpos, traceendpos);
148 if (((int)PRVM_serveredictfloat(ent, flags) & FL_SWIM) && !(SV_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
149 return false; // swim monster left water
151 VectorCopy (traceendpos, PRVM_serveredictvector(ent, origin));
155 SV_LinkEdict_TouchAreaGrid(ent);
160 if (enemy == prog->edicts)
167 // push down from a step height above the wished position
168 neworg[2] += sv_stepheight.value;
169 VectorCopy (neworg, end);
170 end[2] -= sv_stepheight.value*2;
172 trace = SV_TraceBox(neworg, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
174 if (trace.startsolid)
176 neworg[2] -= sv_stepheight.value;
177 trace = SV_TraceBox(neworg, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
178 if (trace.startsolid)
181 if (trace.fraction == 1)
183 // if monster had the ground pulled out, go ahead and fall
184 if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND )
186 VectorAdd (PRVM_serveredictvector(ent, origin), move, PRVM_serveredictvector(ent, origin));
190 SV_LinkEdict_TouchAreaGrid(ent);
192 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
196 return false; // walked off an edge
199 // check point traces down for dangling corners
200 VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
202 if (!SV_CheckBottom (ent))
204 if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND )
205 { // entity had floor mostly pulled out from underneath it
206 // and is trying to correct
210 SV_LinkEdict_TouchAreaGrid(ent);
214 VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
218 if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND )
219 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_PARTIALGROUND;
221 // gameplayfix: check if reached pretty steep plane and bail
222 if ( ! ( (int)PRVM_serveredictfloat(ent, flags) & (FL_SWIM | FL_FLY) ) && sv_gameplayfix_nostepmoveonsteepslopes.integer )
224 if (trace.plane.normal[ 2 ] < 0.5)
226 VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
231 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
237 SV_LinkEdict_TouchAreaGrid(ent);
243 //============================================================================
246 ======================
249 Turns to the movement direction, and walks the current distance if
252 ======================
254 static qboolean SV_StepDirection (prvm_edict_t *ent, float yaw, float dist)
256 prvm_prog_t *prog = SVVM_prog;
257 vec3_t move, oldorigin;
260 PRVM_serveredictfloat(ent, ideal_yaw) = yaw;
263 yaw = yaw*M_PI*2 / 360;
264 move[0] = cos(yaw)*dist;
265 move[1] = sin(yaw)*dist;
268 VectorCopy (PRVM_serveredictvector(ent, origin), oldorigin);
269 if (SV_movestep (ent, move, false, false, false))
271 delta = PRVM_serveredictvector(ent, angles)[YAW] - PRVM_serveredictfloat(ent, ideal_yaw);
272 if (delta > 45 && delta < 315)
273 { // not turned far enough, so don't take the step
274 VectorCopy (oldorigin, PRVM_serveredictvector(ent, origin));
277 SV_LinkEdict_TouchAreaGrid(ent);
281 SV_LinkEdict_TouchAreaGrid(ent);
287 ======================
290 ======================
292 static void SV_FixCheckBottom (prvm_edict_t *ent)
294 prvm_prog_t *prog = SVVM_prog;
295 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_PARTIALGROUND;
307 static void SV_NewChaseDir (prvm_edict_t *actor, prvm_edict_t *enemy, float dist)
309 prvm_prog_t *prog = SVVM_prog;
312 float tdir, olddir, turnaround;
314 olddir = ANGLEMOD((int)(PRVM_serveredictfloat(actor, ideal_yaw)/45)*45);
315 turnaround = ANGLEMOD(olddir - 180);
317 deltax = PRVM_serveredictvector(enemy, origin)[0] - PRVM_serveredictvector(actor, origin)[0];
318 deltay = PRVM_serveredictvector(enemy, origin)[1] - PRVM_serveredictvector(actor, origin)[1];
333 if (d[1] != DI_NODIR && d[2] != DI_NODIR)
336 tdir = d[2] == 90 ? 45 : 315;
338 tdir = d[2] == 90 ? 135 : 215;
340 if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
344 // try other directions
345 if ( ((rand()&3) & 1) || fabs(deltay)>fabs(deltax))
352 if (d[1]!=DI_NODIR && d[1]!=turnaround
353 && SV_StepDirection(actor, d[1], dist))
356 if (d[2]!=DI_NODIR && d[2]!=turnaround
357 && SV_StepDirection(actor, d[2], dist))
360 /* there is no direct path to the player, so pick another direction */
362 if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
365 if (rand()&1) /*randomly determine direction of search*/
367 for (tdir=0 ; tdir<=315 ; tdir += 45)
368 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
373 for (tdir=315 ; tdir >=0 ; tdir -= 45)
374 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
378 if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
381 PRVM_serveredictfloat(actor, ideal_yaw) = olddir; // can't move
383 // if a bridge was pulled out from underneath a monster, it may not have
384 // a valid standing position at all
386 if (!SV_CheckBottom (actor))
387 SV_FixCheckBottom (actor);
392 ======================
395 ======================
397 static qboolean SV_CloseEnough (prvm_edict_t *ent, prvm_edict_t *goal, float dist)
401 for (i=0 ; i<3 ; i++)
403 if (goal->priv.server->areamins[i] > ent->priv.server->areamaxs[i] + dist)
405 if (goal->priv.server->areamaxs[i] < ent->priv.server->areamins[i] - dist)
412 ======================
415 ======================
417 void VM_SV_MoveToGoal(prvm_prog_t *prog)
419 prvm_edict_t *ent, *goal;
422 VM_SAFEPARMCOUNT(1, SV_MoveToGoal);
424 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
425 goal = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, goalentity));
426 dist = PRVM_G_FLOAT(OFS_PARM0);
428 if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
430 PRVM_G_FLOAT(OFS_RETURN) = 0;
434 // if the next step hits the enemy, return immediately
435 if ( PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, enemy)) != prog->edicts && SV_CloseEnough (ent, goal, dist) )
439 if ( (rand()&3)==1 ||
440 !SV_StepDirection (ent, PRVM_serveredictfloat(ent, ideal_yaw), dist))
442 SV_NewChaseDir (ent, goal, dist);