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;
42 float mid, bottom, stepheight;
44 stepheight = sv_stepheight.value + PRVM_serveredictfloat(ent, stepheight_delta);
45 VectorAdd (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
46 VectorAdd (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
48 // if all of the points under the corners are solid world, don't bother
49 // with the tougher checks
50 // the corners must be within 16 of the midpoint
51 start[2] = mins[2] - 1;
52 for (x=0 ; x<=1 ; x++)
53 for (y=0 ; y<=1 ; y++)
55 start[0] = x ? maxs[0] : mins[0];
56 start[1] = y ? maxs[1] : mins[1];
57 if (!(SV_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
62 return true; // we got out easy
67 // check it for real...
71 // the midpoint must be within 16 of the bottom
72 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
73 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
74 stop[2] = start[2] - 2*stepheight;
75 trace = SV_TraceLine(start, stop, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
77 if (trace.fraction == 1.0)
79 mid = bottom = trace.endpos[2];
81 // the corners must be within 16 of the midpoint
82 for (x=0 ; x<=1 ; x++)
83 for (y=0 ; y<=1 ; y++)
85 start[0] = stop[0] = x ? maxs[0] : mins[0];
86 start[1] = stop[1] = y ? maxs[1] : mins[1];
88 trace = SV_TraceLine(start, stop, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
90 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
91 bottom = trace.endpos[2];
92 if (trace.fraction == 1.0 || mid - trace.endpos[2] > stepheight)
105 Called by monster program code.
106 The move will be adjusted for slopes and stairs, but if the move isn't
107 possible, no move is done and false is returned
110 qbool SV_movestep (prvm_edict_t *ent, vec3_t move, qbool relink, qbool noenemy, qbool settrace)
112 prvm_prog_t *prog = SVVM_prog;
113 float dz, stepheight;
114 vec3_t oldorg, neworg, end, traceendpos, entorigin, entmins, entmaxs;
119 stepheight = sv_stepheight.value + PRVM_serveredictfloat(ent, stepheight_delta);
122 VectorCopy (PRVM_serveredictvector(ent, origin), oldorg);
123 VectorAdd (PRVM_serveredictvector(ent, origin), move, neworg);
124 VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
125 VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
127 // flying monsters don't step up
128 if ( (int)PRVM_serveredictfloat(ent, flags) & (FL_SWIM | FL_FLY) )
130 // try one move with vertical motion, then one without
131 for (i=0 ; i<2 ; i++)
133 VectorAdd (PRVM_serveredictvector(ent, origin), move, neworg);
135 enemy = prog->edicts;
138 enemy = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, enemy));
139 if (i == 0 && enemy != prog->edicts)
141 dz = PRVM_serveredictvector(ent, origin)[2] - PRVM_serveredictvector(enemy, origin)[2];
148 VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
149 trace = SV_TraceBox(entorigin, entmins, entmaxs, neworg, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
151 if (trace.fraction == 1)
153 VectorCopy(trace.endpos, traceendpos);
154 if (((int)PRVM_serveredictfloat(ent, flags) & FL_SWIM) && !(SV_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
155 return false; // swim monster left water
157 VectorCopy (traceendpos, PRVM_serveredictvector(ent, origin));
161 SV_LinkEdict_TouchAreaGrid(ent);
166 if (enemy == prog->edicts)
173 // push down from a step height above the wished position
174 neworg[2] += stepheight;
175 VectorCopy (neworg, end);
176 end[2] -= stepheight*2;
178 trace = SV_TraceBox(neworg, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
180 if (trace.startsolid)
182 neworg[2] -= stepheight;
183 trace = SV_TraceBox(neworg, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
184 if (trace.startsolid)
187 if (trace.fraction == 1)
189 // if monster had the ground pulled out, go ahead and fall
190 if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND )
192 VectorAdd (PRVM_serveredictvector(ent, origin), move, PRVM_serveredictvector(ent, origin));
196 SV_LinkEdict_TouchAreaGrid(ent);
198 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
202 return false; // walked off an edge
205 // check point traces down for dangling corners
206 VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
208 if (!SV_CheckBottom (ent))
210 if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND )
211 { // entity had floor mostly pulled out from underneath it
212 // and is trying to correct
216 SV_LinkEdict_TouchAreaGrid(ent);
220 VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
224 if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND )
225 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_PARTIALGROUND;
227 // gameplayfix: check if reached pretty steep plane and bail
228 if ( ! ( (int)PRVM_serveredictfloat(ent, flags) & (FL_SWIM | FL_FLY) ) && sv_gameplayfix_nostepmoveonsteepslopes.integer )
230 if (trace.plane.normal[ 2 ] < 0.5)
232 VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
237 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
243 SV_LinkEdict_TouchAreaGrid(ent);
249 //============================================================================
252 ======================
255 Turns to the movement direction, and walks the current distance if
258 ======================
260 static qbool SV_StepDirection (prvm_edict_t *ent, float yaw, float dist)
262 prvm_prog_t *prog = SVVM_prog;
263 vec3_t move, oldorigin;
266 PRVM_serveredictfloat(ent, ideal_yaw) = yaw;
269 yaw = yaw*M_PI*2 / 360;
270 move[0] = cos(yaw)*dist;
271 move[1] = sin(yaw)*dist;
274 VectorCopy (PRVM_serveredictvector(ent, origin), oldorigin);
275 if (SV_movestep (ent, move, false, false, false))
277 delta = PRVM_serveredictvector(ent, angles)[YAW] - PRVM_serveredictfloat(ent, ideal_yaw);
278 if (delta > 45 && delta < 315)
279 { // not turned far enough, so don't take the step
280 VectorCopy (oldorigin, PRVM_serveredictvector(ent, origin));
283 SV_LinkEdict_TouchAreaGrid(ent);
287 SV_LinkEdict_TouchAreaGrid(ent);
293 ======================
296 ======================
298 static void SV_FixCheckBottom (prvm_edict_t *ent)
300 prvm_prog_t *prog = SVVM_prog;
301 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_PARTIALGROUND;
313 static void SV_NewChaseDir (prvm_edict_t *actor, prvm_edict_t *enemy, float dist)
315 prvm_prog_t *prog = SVVM_prog;
318 float tdir, olddir, turnaround;
320 olddir = ANGLEMOD((int)(PRVM_serveredictfloat(actor, ideal_yaw)/45)*45);
321 turnaround = ANGLEMOD(olddir - 180);
323 deltax = PRVM_serveredictvector(enemy, origin)[0] - PRVM_serveredictvector(actor, origin)[0];
324 deltay = PRVM_serveredictvector(enemy, origin)[1] - PRVM_serveredictvector(actor, origin)[1];
339 if (d[1] != DI_NODIR && d[2] != DI_NODIR)
342 tdir = d[2] == 90 ? 45 : 315;
344 tdir = d[2] == 90 ? 135 : 215;
346 if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
350 // try other directions
351 if ( ((rand()&3) & 1) || fabs(deltay)>fabs(deltax))
358 if (d[1]!=DI_NODIR && d[1]!=turnaround
359 && SV_StepDirection(actor, d[1], dist))
362 if (d[2]!=DI_NODIR && d[2]!=turnaround
363 && SV_StepDirection(actor, d[2], dist))
366 /* there is no direct path to the player, so pick another direction */
368 if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
371 if (rand()&1) /*randomly determine direction of search*/
373 for (tdir=0 ; tdir<=315 ; tdir += 45)
374 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
379 for (tdir=315 ; tdir >=0 ; tdir -= 45)
380 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
384 if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
387 PRVM_serveredictfloat(actor, ideal_yaw) = olddir; // can't move
389 // if a bridge was pulled out from underneath a monster, it may not have
390 // a valid standing position at all
392 if (!SV_CheckBottom (actor))
393 SV_FixCheckBottom (actor);
398 ======================
401 ======================
403 static qbool SV_CloseEnough (prvm_edict_t *ent, prvm_edict_t *goal, float dist)
407 for (i=0 ; i<3 ; i++)
409 if (goal->priv.server->areamins[i] > ent->priv.server->areamaxs[i] + dist)
411 if (goal->priv.server->areamaxs[i] < ent->priv.server->areamins[i] - dist)
418 ======================
421 ======================
423 void VM_SV_MoveToGoal(prvm_prog_t *prog)
425 prvm_edict_t *ent, *goal;
428 VM_SAFEPARMCOUNT(1, VM_SV_MoveToGoal);
430 ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
431 goal = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, goalentity));
432 dist = PRVM_G_FLOAT(OFS_PARM0);
434 if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
436 PRVM_G_FLOAT(OFS_RETURN) = 0;
440 // if the next step hits the enemy, return immediately
441 if ( PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, enemy)) != prog->edicts && SV_CloseEnough (ent, goal, dist) )
445 if ( (rand()&3)==1 ||
446 !SV_StepDirection (ent, PRVM_serveredictfloat(ent, ideal_yaw), dist))
448 SV_NewChaseDir (ent, goal, dist);