1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20 // sv_move.c -- monster movement
21
22 #include "quakedef.h"
23
24 #define STEPSIZE 18
25
26 /*
27 =============
28 SV_CheckBottom
29
30 Returns false if any part of the bottom of the entity is off an edge that
31 is not a staircase.
32
33 =============
34 */
35 int c_yes, c_no;
36
SV_CheckBottom(edict_t * ent)37 qboolean SV_CheckBottom (edict_t *ent)
38 {
39 vec3_t mins, maxs, start, stop;
40 trace_t trace;
41 int x, y;
42 float mid, bottom;
43
44 VectorAdd (ent->u.v.origin, ent->u.v.mins, mins);
45 VectorAdd (ent->u.v.origin, ent->u.v.maxs, maxs);
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];
56 if (SV_PointContents (start) != CONTENTS_SOLID)
57 goto realcheck;
58 }
59
60 c_yes++;
61 return true; // we got out easy
62
63 realcheck:
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*STEPSIZE;
74 trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent);
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
87 trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent);
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] > STEPSIZE)
92 return false;
93 }
94
95 c_yes++;
96 return true;
97 }
98
99
100 /*
101 =============
102 SV_movestep
103
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, false is returned, and
107 pr_global_struct->trace_normal is set to the normal of the blocking wall
108 =============
109 */
SV_movestep(edict_t * ent,vec3_t move,qboolean relink)110 qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
111 {
112 float dz;
113 vec3_t oldorg, neworg, end;
114 trace_t trace;
115 int i;
116 edict_t *enemy;
117
118 // try the move
119 VectorCopy (ent->u.v.origin, oldorg);
120 VectorAdd (ent->u.v.origin, move, neworg);
121
122 // flying monsters don't step up
123 if ( (int)ent->u.v.flags & (FL_SWIM | FL_FLY) )
124 {
125 // try one move with vertical motion, then one without
126 for (i=0 ; i<2 ; i++)
127 {
128 VectorAdd (ent->u.v.origin, move, neworg);
129 enemy = PROG_TO_EDICT(ent->u.v.enemy);
130 if (i == 0 && enemy != sv.edicts)
131 {
132 dz = ent->u.v.origin[2] - PROG_TO_EDICT(ent->u.v.enemy)->u.v.origin[2];
133 if (dz > 40)
134 neworg[2] -= 8;
135 if (dz < 30)
136 neworg[2] += 8;
137 }
138 trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, neworg, false, ent);
139
140 if (trace.fraction == 1)
141 {
142 if ( ((int)ent->u.v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY )
143 return false; // swim monster left water
144
145 VectorCopy (trace.endpos, ent->u.v.origin);
146 if (relink)
147 SV_LinkEdict (ent, true);
148 return true;
149 }
150
151 if (enemy == sv.edicts)
152 break;
153 }
154
155 return false;
156 }
157
158 // push down from a step height above the wished position
159 neworg[2] += STEPSIZE;
160 VectorCopy (neworg, end);
161 end[2] -= STEPSIZE*2;
162
163 trace = SV_Move (neworg, ent->u.v.mins, ent->u.v.maxs, end, false, ent);
164
165 if (trace.allsolid)
166 return false;
167
168 if (trace.startsolid)
169 {
170 neworg[2] -= STEPSIZE;
171 trace = SV_Move (neworg, ent->u.v.mins, ent->u.v.maxs, end, false, ent);
172 if (trace.allsolid || trace.startsolid)
173 return false;
174 }
175 if (trace.fraction == 1)
176 {
177 // if monster had the ground pulled out, go ahead and fall
178 if ( (int)ent->u.v.flags & FL_PARTIALGROUND )
179 {
180 VectorAdd (ent->u.v.origin, move, ent->u.v.origin);
181 if (relink)
182 SV_LinkEdict (ent, true);
183 ent->u.v.flags = (int)ent->u.v.flags & ~FL_ONGROUND;
184 // Con_Printf ("fall down\n");
185 return true;
186 }
187
188 return false; // walked off an edge
189 }
190
191 // check point traces down for dangling corners
192 VectorCopy (trace.endpos, ent->u.v.origin);
193
194 if (!SV_CheckBottom (ent))
195 {
196 if ( (int)ent->u.v.flags & FL_PARTIALGROUND )
197 { // entity had floor mostly pulled out from underneath it
198 // and is trying to correct
199 if (relink)
200 SV_LinkEdict (ent, true);
201 return true;
202 }
203 VectorCopy (oldorg, ent->u.v.origin);
204 return false;
205 }
206
207 if ( (int)ent->u.v.flags & FL_PARTIALGROUND )
208 {
209 // Con_Printf ("back on ground\n");
210 ent->u.v.flags = (int)ent->u.v.flags & ~FL_PARTIALGROUND;
211 }
212 ent->u.v.groundentity = EDICT_TO_PROG(trace.ent);
213
214 // the move is ok
215 if (relink)
216 SV_LinkEdict (ent, true);
217 return true;
218 }
219
220
221 //============================================================================
222
223 /*
224 ======================
225 SV_StepDirection
226
227 Turns to the movement direction, and walks the current distance if
228 facing it.
229
230 ======================
231 */
232 void PF_changeyaw (void);
SV_StepDirection(edict_t * ent,float yaw,float dist)233 qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
234 {
235 vec3_t move, oldorigin;
236 float delta;
237
238 ent->u.v.ideal_yaw = yaw;
239 PF_changeyaw();
240
241 yaw = yaw*M_PI*2 / 360;
242 move[0] = cos(yaw)*dist;
243 move[1] = sin(yaw)*dist;
244 move[2] = 0;
245
246 VectorCopy (ent->u.v.origin, oldorigin);
247 if (SV_movestep (ent, move, false))
248 {
249 delta = ent->u.v.angles[YAW] - ent->u.v.ideal_yaw;
250 if (delta > 45 && delta < 315)
251 { // not turned far enough, so don't take the step
252 VectorCopy (oldorigin, ent->u.v.origin);
253 }
254 SV_LinkEdict (ent, true);
255 return true;
256 }
257 SV_LinkEdict (ent, true);
258
259 return false;
260 }
261
262 /*
263 ======================
264 SV_FixCheckBottom
265
266 ======================
267 */
SV_FixCheckBottom(edict_t * ent)268 void SV_FixCheckBottom (edict_t *ent)
269 {
270 // Con_Printf ("SV_FixCheckBottom\n");
271
272 ent->u.v.flags = (int)ent->u.v.flags | FL_PARTIALGROUND;
273 }
274
275
276
277 /*
278 ================
279 SV_NewChaseDir
280
281 ================
282 */
283 #define DI_NODIR -1
SV_NewChaseDir(edict_t * actor,edict_t * enemy,float dist)284 void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
285 {
286 float deltax,deltay;
287 float d[3];
288 float tdir, olddir, turnaround;
289
290 olddir = anglemod( (int)(actor->u.v.ideal_yaw/45)*45 );
291 turnaround = anglemod(olddir - 180);
292
293 deltax = enemy->u.v.origin[0] - actor->u.v.origin[0];
294 deltay = enemy->u.v.origin[1] - actor->u.v.origin[1];
295 if (deltax>10)
296 d[1]= 0;
297 else if (deltax<-10)
298 d[1]= 180;
299 else
300 d[1]= DI_NODIR;
301 if (deltay<-10)
302 d[2]= 270;
303 else if (deltay>10)
304 d[2]= 90;
305 else
306 d[2]= DI_NODIR;
307
308 // try direct route
309 if (d[1] != DI_NODIR && d[2] != DI_NODIR)
310 {
311 if (d[1] == 0)
312 tdir = d[2] == 90 ? 45 : 315;
313 else
314 tdir = d[2] == 90 ? 135 : 215;
315
316 if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
317 return;
318 }
319
320 // try other directions
321 if ( ((rand()&3) & 1) || abs((int) deltay)>abs((int) deltax))
322 {
323 tdir=d[1];
324 d[1]=d[2];
325 d[2]=tdir;
326 }
327
328 if (d[1]!=DI_NODIR && d[1]!=turnaround
329 && SV_StepDirection(actor, d[1], dist))
330 return;
331
332 if (d[2]!=DI_NODIR && d[2]!=turnaround
333 && SV_StepDirection(actor, d[2], dist))
334 return;
335
336 /* there is no direct path to the player, so pick another direction */
337
338 if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
339 return;
340
341 if (rand()&1) /*randomly determine direction of search*/
342 {
343 for (tdir=0 ; tdir<=315 ; tdir += 45)
344 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
345 return;
346 }
347 else
348 {
349 for (tdir=315 ; tdir >=0 ; tdir -= 45)
350 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
351 return;
352 }
353
354 if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
355 return;
356
357 actor->u.v.ideal_yaw = olddir; // can't move
358
359 // if a bridge was pulled out from underneath a monster, it may not have
360 // a valid standing position at all
361
362 if (!SV_CheckBottom (actor))
363 SV_FixCheckBottom (actor);
364
365 }
366
367 /*
368 ======================
369 SV_CloseEnough
370
371 ======================
372 */
SV_CloseEnough(edict_t * ent,edict_t * goal,float dist)373 qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
374 {
375 int i;
376
377 for (i=0 ; i<3 ; i++)
378 {
379 if (goal->u.v.absmin[i] > ent->u.v.absmax[i] + dist)
380 return false;
381 if (goal->u.v.absmax[i] < ent->u.v.absmin[i] - dist)
382 return false;
383 }
384 return true;
385 }
386
387 /*
388 ======================
389 SV_MoveToGoal
390
391 ======================
392 */
SV_MoveToGoal(void)393 void SV_MoveToGoal (void)
394 {
395 edict_t *ent, *goal;
396 float dist;
397 #ifdef QUAKE2
398 edict_t *enemy;
399 #endif
400
401 ent = PROG_TO_EDICT(pr_global_struct->self);
402 goal = PROG_TO_EDICT(ent->u.v.goalentity);
403 dist = G_FLOAT(OFS_PARM0);
404
405 if ( !( (int)ent->u.v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
406 {
407 G_FLOAT(OFS_RETURN) = 0;
408 return;
409 }
410
411 // if the next step hits the enemy, return immediately
412 #ifdef QUAKE2
413 enemy = PROG_TO_EDICT(ent->u.v.enemy);
414 if (enemy != sv.edicts && SV_CloseEnough (ent, enemy, dist) )
415 #else
416 if ( PROG_TO_EDICT(ent->u.v.enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) )
417 #endif
418 return;
419
420 // bump around...
421 if ( (rand()&3)==1 ||
422 !SV_StepDirection (ent, ent->u.v.ideal_yaw, dist))
423 {
424 SV_NewChaseDir (ent, goal, dist);
425 }
426 }
427
428