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