DarkPlaces
Game engine based on the Quake 1 engine by id Software, developed by LadyHavoc
 
sv_move.c
Go to the documentation of this file.
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// sv_move.c -- monster movement
21
22#include "quakedef.h"
23#include "prvm_cmds.h"
24
25/*
26=============
27SV_CheckBottom
28
29Returns false if any part of the bottom of the entity is off an edge that
30is not a staircase.
31
32=============
33*/
35
37{
38 prvm_prog_t *prog = SVVM_prog;
39 vec3_t mins, maxs, start, stop;
40 trace_t trace;
41 int x, y;
42 float mid, bottom;
43
46
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++)
53 {
54 start[0] = x ? maxs[0] : mins[0];
55 start[1] = y ? maxs[1] : mins[1];
57 goto realcheck;
58 }
59
60 c_yes++;
61 return true; // we got out easy
62
63realcheck:
64 c_no++;
65//
66// check it for real...
67//
68 start[2] = mins[2];
69
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;
75
76 if (trace.fraction == 1.0)
77 return false;
78 mid = bottom = trace.endpos[2];
79
80// the corners must be within 16 of the midpoint
81 for (x=0 ; x<=1 ; x++)
82 for (y=0 ; y<=1 ; y++)
83 {
84 start[0] = stop[0] = x ? maxs[0] : mins[0];
85 start[1] = stop[1] = y ? maxs[1] : mins[1];
86
88
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)
92 return false;
93 }
94
95 c_yes++;
96 return true;
97}
98
99
100/*
101=============
102SV_movestep
103
104Called by monster program code.
105The move will be adjusted for slopes and stairs, but if the move isn't
106possible, no move is done and false is returned
107=============
108*/
109qbool SV_movestep (prvm_edict_t *ent, vec3_t move, qbool relink, qbool noenemy, qbool settrace)
110{
111 prvm_prog_t *prog = SVVM_prog;
112 float dz;
113 vec3_t oldorg, neworg, end, traceendpos, entorigin, entmins, entmaxs;
114 trace_t trace;
115 int i;
117
118// try the move
120 VectorAdd (PRVM_serveredictvector(ent, origin), move, neworg);
121 VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
122 VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
123
124// flying monsters don't step up
125 if ( (int)PRVM_serveredictfloat(ent, flags) & (FL_SWIM | FL_FLY) )
126 {
127 // try one move with vertical motion, then one without
128 for (i=0 ; i<2 ; i++)
129 {
130 VectorAdd (PRVM_serveredictvector(ent, origin), move, neworg);
131 if (noenemy)
132 enemy = prog->edicts;
133 else
134 {
136 if (i == 0 && enemy != prog->edicts)
137 {
139 if (dz > 40)
140 neworg[2] -= 8;
141 if (dz < 30)
142 neworg[2] += 8;
143 }
144 }
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);
147
148 if (trace.fraction == 1)
149 {
150 VectorCopy(trace.endpos, traceendpos);
152 return false; // swim monster left water
153
154 VectorCopy (traceendpos, PRVM_serveredictvector(ent, origin));
155 if (relink)
156 {
157 SV_LinkEdict(ent);
159 }
160 return true;
161 }
162
163 if (enemy == prog->edicts)
164 break;
165 }
166
167 return false;
168 }
169
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;
174
175 trace = SV_TraceBox(neworg, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
176
177 if (trace.startsolid)
178 {
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)
182 return false;
183 }
184 if (trace.fraction == 1)
185 {
186 // if monster had the ground pulled out, go ahead and fall
188 {
190 if (relink)
191 {
192 SV_LinkEdict(ent);
194 }
195 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
196 return true;
197 }
198
199 return false; // walked off an edge
200 }
201
202// check point traces down for dangling corners
204
205 if (!SV_CheckBottom (ent))
206 {
208 { // entity had floor mostly pulled out from underneath it
209 // and is trying to correct
210 if (relink)
211 {
212 SV_LinkEdict(ent);
214 }
215 return true;
216 }
218 return false;
219 }
220
222 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_PARTIALGROUND;
223
224// gameplayfix: check if reached pretty steep plane and bail
226 {
227 if (trace.plane.normal[ 2 ] < 0.5)
228 {
230 return false;
231 }
232 }
233
235
236// the move is ok
237 if (relink)
238 {
239 SV_LinkEdict(ent);
241 }
242 return true;
243}
244
245
246//============================================================================
247
248/*
249======================
250SV_StepDirection
251
252Turns to the movement direction, and walks the current distance if
253facing it.
254
255======================
256*/
257static qbool SV_StepDirection (prvm_edict_t *ent, float yaw, float dist)
258{
259 prvm_prog_t *prog = SVVM_prog;
260 vec3_t move, oldorigin;
261 float delta;
262
264 VM_changeyaw(prog);
265
266 yaw = yaw*M_PI*2 / 360;
267 move[0] = cos(yaw)*dist;
268 move[1] = sin(yaw)*dist;
269 move[2] = 0;
270
272 if (SV_movestep (ent, move, false, false, false))
273 {
275 if (delta > 45 && delta < 315)
276 { // not turned far enough, so don't take the step
278 }
279 SV_LinkEdict(ent);
281 return true;
282 }
283 SV_LinkEdict(ent);
285
286 return false;
287}
288
289/*
290======================
291SV_FixCheckBottom
292
293======================
294*/
300
301
302
303/*
304================
305SV_NewChaseDir
306
307================
308*/
309#define DI_NODIR -1
310static void SV_NewChaseDir (prvm_edict_t *actor, prvm_edict_t *enemy, float dist)
311{
312 prvm_prog_t *prog = SVVM_prog;
313 float deltax,deltay;
314 float d[3];
315 float tdir, olddir, turnaround;
316
317 olddir = ANGLEMOD((int)(PRVM_serveredictfloat(actor, ideal_yaw)/45)*45);
318 turnaround = ANGLEMOD(olddir - 180);
319
322 if (deltax>10)
323 d[1]= 0;
324 else if (deltax<-10)
325 d[1]= 180;
326 else
327 d[1]= DI_NODIR;
328 if (deltay<-10)
329 d[2]= 270;
330 else if (deltay>10)
331 d[2]= 90;
332 else
333 d[2]= DI_NODIR;
334
335// try direct route
336 if (d[1] != DI_NODIR && d[2] != DI_NODIR)
337 {
338 if (d[1] == 0)
339 tdir = d[2] == 90 ? 45 : 315;
340 else
341 tdir = d[2] == 90 ? 135 : 215;
342
343 if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
344 return;
345 }
346
347// try other directions
348 if ( ((rand()&3) & 1) || fabs(deltay)>fabs(deltax))
349 {
350 tdir=d[1];
351 d[1]=d[2];
352 d[2]=tdir;
353 }
354
355 if (d[1]!=DI_NODIR && d[1]!=turnaround
356 && SV_StepDirection(actor, d[1], dist))
357 return;
358
359 if (d[2]!=DI_NODIR && d[2]!=turnaround
360 && SV_StepDirection(actor, d[2], dist))
361 return;
362
363/* there is no direct path to the player, so pick another direction */
364
365 if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
366 return;
367
368 if (rand()&1) /*randomly determine direction of search*/
369 {
370 for (tdir=0 ; tdir<=315 ; tdir += 45)
371 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
372 return;
373 }
374 else
375 {
376 for (tdir=315 ; tdir >=0 ; tdir -= 45)
377 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
378 return;
379 }
380
381 if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
382 return;
383
384 PRVM_serveredictfloat(actor, ideal_yaw) = olddir; // can't move
385
386// if a bridge was pulled out from underneath a monster, it may not have
387// a valid standing position at all
388
389 if (!SV_CheckBottom (actor))
390 SV_FixCheckBottom (actor);
391
392}
393
394/*
395======================
396SV_CloseEnough
397
398======================
399*/
400static qbool SV_CloseEnough (prvm_edict_t *ent, prvm_edict_t *goal, float dist)
401{
402 int i;
403
404 for (i=0 ; i<3 ; i++)
405 {
406 if (goal->priv.server->areamins[i] > ent->priv.server->areamaxs[i] + dist)
407 return false;
408 if (goal->priv.server->areamaxs[i] < ent->priv.server->areamins[i] - dist)
409 return false;
410 }
411 return true;
412}
413
414/*
415======================
416VM_SV_MoveToGoal
417
418======================
419*/
421{
422 prvm_edict_t *ent, *goal;
423 float dist;
424
426
429 dist = PRVM_G_FLOAT(OFS_PARM0);
430
431 if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
432 {
434 return;
435 }
436
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) )
439 return;
440
441// bump around...
442 if ( (rand()&3)==1 ||
444 {
445 SV_NewChaseDir (ent, goal, dist);
446 }
447}
448
#define SUPERCONTENTS_BODY
Definition bspfile.h:201
#define SUPERCONTENTS_SOLID
Definition bspfile.h:196
#define SUPERCONTENTS_LIQUIDSMASK
Definition bspfile.h:218
cvar_t collision_extendmovelength
Definition collision.c:14
float flags
entity self
vector mins
vector maxs
entity enemy
vector angles
vector origin
vector oldorigin
static int(ZEXPORT *qz_inflate)(z_stream *strm
GLint GLenum GLint GLint y
Definition glquake.h:651
GLint GLenum GLint x
Definition glquake.h:651
#define ANGLEMOD(a)
Definition mathlib.h:67
#define VectorCopy(in, out)
Definition mathlib.h:101
#define VectorAdd(a, b, out)
Definition mathlib.h:100
#define M_PI
Definition mathlib.h:28
float cos(float f)
float sin(float f)
float fabs(float f)
#define OFS_RETURN
Definition pr_comp.h:33
#define OFS_PARM0
Definition pr_comp.h:34
float ideal_yaw
Definition progsdefs.qc:184
entity goalentity
Definition progsdefs.qc:189
entity groundentity
Definition progsdefs.qc:134
#define PRVM_serveredictvector(ed, fieldname)
Definition progsvm.h:173
#define PRVM_serverglobaledict(fieldname)
Definition progsvm.h:180
#define PRVM_serveredictedict(ed, fieldname)
Definition progsvm.h:175
#define PRVM_EDICT_TO_PROG(e)
Definition progsvm.h:875
#define PRVM_PROG_TO_EDICT(n)
Definition progsvm.h:877
#define PRVM_serveredictfloat(ed, fieldname)
Definition progsvm.h:172
#define PRVM_G_FLOAT(o)
Definition progsvm.h:882
#define SVVM_prog
Definition progsvm.h:766
void VM_changeyaw(prvm_prog_t *prog)
Definition prvm_cmds.c:4747
#define VM_SAFEPARMCOUNT(p, f)
Definition prvm_cmds.h:207
int i
vec_t vec3_t[3]
Definition qtypes.h:71
bool qbool
Definition qtypes.h:9
#define YAW
Definition qtypes.h:19
#define FL_FLY
Definition server.h:357
trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
Definition sv_phys.c:256
void SV_LinkEdict(prvm_edict_t *ent)
Definition sv_phys.c:804
#define FL_PARTIALGROUND
not all corners are valid
Definition server.h:367
int SV_GenericHitSuperContentsMask(const prvm_edict_t *edict)
calculates hitsupercontentsmask for a generic qc entity
Definition sv_phys.c:73
cvar_t sv_stepheight
Definition sv_main.c:153
int SV_PointSuperContents(const vec3_t point)
Definition sv_phys.c:611
#define FL_ONGROUND
Definition server.h:366
cvar_t sv_gameplayfix_nostepmoveonsteepslopes
Definition sv_main.c:125
trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
traces a box move against worldmodel and all entities in the specified area
Definition sv_phys.c:414
#define FL_SWIM
Definition server.h:358
void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent)
Definition sv_phys.c:727
float value
Definition cvar.h:74
int integer
Definition cvar.h:73
union prvm_edict_t::@29 priv
struct edict_engineprivate_s * server
FIXME: this server pointer really means world, not server (it is used by both server qc and client qc...
Definition progsvm.h:106
prvm_edict_t * edicts
Definition progsvm.h:680
void * ent
Definition collision.h:47
double fraction
Definition collision.h:40
double endpos[3]
Definition collision.h:42
plane_t plane
Definition collision.h:44
qbool startsolid
Definition collision.h:26
static void SV_NewChaseDir(prvm_edict_t *actor, prvm_edict_t *enemy, float dist)
Definition sv_move.c:310
qbool SV_CheckBottom(prvm_edict_t *ent)
Definition sv_move.c:36
int c_yes
Definition sv_move.c:34
#define DI_NODIR
Definition sv_move.c:309
void VM_SV_MoveToGoal(prvm_prog_t *prog)
Definition sv_move.c:420
static void SV_FixCheckBottom(prvm_edict_t *ent)
Definition sv_move.c:295
static qbool SV_CloseEnough(prvm_edict_t *ent, prvm_edict_t *goal, float dist)
Definition sv_move.c:400
int c_no
Definition sv_move.c:34
static qbool SV_StepDirection(prvm_edict_t *ent, float yaw, float dist)
Definition sv_move.c:257
qbool SV_movestep(prvm_edict_t *ent, vec3_t move, qbool relink, qbool noenemy, qbool settrace)
Definition sv_move.c:109
vec3_t normal
Definition collision.h:13
#define MOVE_NORMAL
Definition world.h:28
#define MOVE_NOMONSTERS
Definition world.h:29