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 qbool 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), 0, 0, collision_extendmovelength.value);
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), 0, 0, collision_extendmovelength.value);
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 qbool SV_movestep (prvm_edict_t *ent, vec3_t move, qbool relink, qbool noenemy, qbool settrace)
111 prvm_prog_t *prog = SVVM_prog;
113 vec3_t oldorg, neworg, end, traceendpos, entorigin, entmins, entmaxs;
119 VectorCopy (PRVM_serveredictvector(ent, origin), oldorg);
120 VectorAdd (PRVM_serveredictvector(ent, origin), move, neworg);
121 VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
122 VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
124 // flying monsters don't step up
125 if ( (int)PRVM_serveredictfloat(ent, flags) & (FL_SWIM | FL_FLY) )
127 // try one move with vertical motion, then one without
128 for (i=0 ; i<2 ; i++)
130 VectorAdd (PRVM_serveredictvector(ent, origin), move, neworg);
132 enemy = prog->edicts;
135 enemy = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, enemy));
136 if (i == 0 && enemy != prog->edicts)
138 dz = PRVM_serveredictvector(ent, origin)[2] - PRVM_serveredictvector(enemy, origin)[2];
145 VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
146 trace = SV_TraceBox(entorigin, entmins, entmaxs, neworg, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
148 if (trace.fraction == 1)
150 VectorCopy(trace.endpos, traceendpos);
151 if (((int)PRVM_serveredictfloat(ent, flags) & FL_SWIM) && !(SV_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
152 return false; // swim monster left water
154 VectorCopy (traceendpos, PRVM_serveredictvector(ent, origin));
158 SV_LinkEdict_TouchAreaGrid(ent);
163 if (enemy == prog->edicts)
170 // push down from a step height above the wished position
171 neworg[2] += sv_stepheight.value;
172 VectorCopy (neworg, end);
173 end[2] -= sv_stepheight.value*2;
175 trace = SV_TraceBox(neworg, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
177 if (trace.startsolid)
179 neworg[2] -= sv_stepheight.value;
180 trace = SV_TraceBox(neworg, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
181 if (trace.startsolid)
184 if (trace.fraction == 1)
186 // if monster had the ground pulled out, go ahead and fall
187 if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND )
189 VectorAdd (PRVM_serveredictvector(ent, origin), move, PRVM_serveredictvector(ent, origin));
193 SV_LinkEdict_TouchAreaGrid(ent);
195 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
199 return false; // walked off an edge
202 // check point traces down for dangling corners
203 VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
205 if (!SV_CheckBottom (ent))
207 if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND )
208 { // entity had floor mostly pulled out from underneath it
209 // and is trying to correct
213 SV_LinkEdict_TouchAreaGrid(ent);
217 VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
221 if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND )
222 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_PARTIALGROUND;
224 // gameplayfix: check if reached pretty steep plane and bail
225 if ( ! ( (int)PRVM_serveredictfloat(ent, flags) & (FL_SWIM | FL_FLY) ) && sv_gameplayfix_nostepmoveonsteepslopes.integer )
227 if (trace.plane.normal[ 2 ] < 0.5)
229 VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
234 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
240 SV_LinkEdict_TouchAreaGrid(ent);
246 //============================================================================
249 ======================
252 Turns to the movement direction, and walks the current distance if
255 ======================
257 static qbool SV_StepDirection (prvm_edict_t *ent, float yaw, float dist)
259 prvm_prog_t *prog = SVVM_prog;
260 vec3_t move, oldorigin;
263 PRVM_serveredictfloat(ent, ideal_yaw) = yaw;
266 yaw = yaw*M_PI*2 / 360;
267 move[0] = cos(yaw)*dist;
268 move[1] = sin(yaw)*dist;
271 VectorCopy (PRVM_serveredictvector(ent, origin), oldorigin);
272 if (SV_movestep (ent, move, false, false, false))
274 delta = PRVM_serveredictvector(ent, angles)[YAW] - PRVM_serveredictfloat(ent, ideal_yaw);
275 if (delta > 45 && delta < 315)
276 { // not turned far enough, so don't take the step
277 VectorCopy (oldorigin, PRVM_serveredictvector(ent, origin));
280 SV_LinkEdict_TouchAreaGrid(ent);
284 SV_LinkEdict_TouchAreaGrid(ent);
290 ======================
293 ======================
295 static void SV_FixCheckBottom (prvm_edict_t *ent)
297 prvm_prog_t *prog = SVVM_prog;
298 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_PARTIALGROUND;
310 static void SV_NewChaseDir (prvm_edict_t *actor, prvm_edict_t *enemy, float dist)
312 prvm_prog_t *prog = SVVM_prog;
315 float tdir, olddir, turnaround;
317 olddir = ANGLEMOD((int)(PRVM_serveredictfloat(actor, ideal_yaw)/45)*45);
318 turnaround = ANGLEMOD(olddir - 180);
320 deltax = PRVM_serveredictvector(enemy, origin)[0] - PRVM_serveredictvector(actor, origin)[0];
321 deltay = PRVM_serveredictvector(enemy, origin)[1] - PRVM_serveredictvector(actor, origin)[1];
336 if (d[1] != DI_NODIR && d[2] != DI_NODIR)
339 tdir = d[2] == 90 ? 45 : 315;
341 tdir = d[2] == 90 ? 135 : 215;
343 if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
347 // try other directions
348 if ( ((rand()&3) & 1) || fabs(deltay)>fabs(deltax))
355 if (d[1]!=DI_NODIR && d[1]!=turnaround
356 && SV_StepDirection(actor, d[1], dist))
359 if (d[2]!=DI_NODIR && d[2]!=turnaround
360 && SV_StepDirection(actor, d[2], dist))
363 /* there is no direct path to the player, so pick another direction */
365 if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
368 if (rand()&1) /*randomly determine direction of search*/
370 for (tdir=0 ; tdir<=315 ; tdir += 45)
371 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
376 for (tdir=315 ; tdir >=0 ; tdir -= 45)
377 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
381 if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
384 PRVM_serveredictfloat(actor, ideal_yaw) = olddir; // can't move
386 // if a bridge was pulled out from underneath a monster, it may not have
387 // a valid standing position at all
389 if (!SV_CheckBottom (actor))
390 SV_FixCheckBottom (actor);
395 ======================
398 ======================
400 static qbool SV_CloseEnough (prvm_edict_t *ent, prvm_edict_t *goal, float dist)
404 for (i=0 ; i<3 ; i++)
406 if (goal->priv.server->areamins[i] > ent->priv.server->areamaxs[i] + dist)
408 if (goal->priv.server->areamaxs[i] < ent->priv.server->areamins[i] - dist)
415 ======================
418 ======================
420 void VM_SV_MoveToGoal(prvm_prog_t *prog)
422 prvm_edict_t *ent, *goal;
425 VM_SAFEPARMCOUNT(1, VM_SV_MoveToGoal);
427 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
428 goal = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, goalentity));
429 dist = PRVM_G_FLOAT(OFS_PARM0);
431 if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
433 PRVM_G_FLOAT(OFS_RETURN) = 0;
437 // if the next step hits the enemy, return immediately
438 if ( PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, enemy)) != prog->edicts && SV_CloseEnough (ent, goal, dist) )
442 if ( (rand()&3)==1 ||
443 !SV_StepDirection (ent, PRVM_serveredictfloat(ent, ideal_yaw), dist))
445 SV_NewChaseDir (ent, goal, dist);