7c0b0ff1d3927fdf977873768713e4dc86634473
[divverent/darkplaces.git] / sv_move.c
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 /*
25 =============
26 SV_CheckBottom
27
28 Returns false if any part of the bottom of the entity is off an edge that
29 is not a staircase.
30
31 =============
32 */
33 int c_yes, c_no;
34
35 qboolean SV_CheckBottom (edict_t *ent)
36 {
37         vec3_t  mins, maxs, start, stop;
38         trace_t trace;
39         int             x, y;
40         float   mid, bottom;
41
42         VectorAdd (ent->v->origin, ent->v->mins, mins);
43         VectorAdd (ent->v->origin, ent->v->maxs, maxs);
44
45 // if all of the points under the corners are solid world, don't bother
46 // with the tougher checks
47 // the corners must be within 16 of the midpoint
48         start[2] = mins[2] - 1;
49         for     (x=0 ; x<=1 ; x++)
50                 for     (y=0 ; y<=1 ; y++)
51                 {
52                         start[0] = x ? maxs[0] : mins[0];
53                         start[1] = y ? maxs[1] : mins[1];
54                         if (sv.worldmodel->PointContents(sv.worldmodel, start) != CONTENTS_SOLID)
55                                 goto realcheck;
56                 }
57
58         c_yes++;
59         return true;            // we got out easy
60
61 realcheck:
62         c_no++;
63 //
64 // check it for real...
65 //
66         start[2] = mins[2];
67
68 // the midpoint must be within 16 of the bottom
69         start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
70         start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
71         stop[2] = start[2] - 2*sv_stepheight.value;
72         trace = SV_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent);
73
74         if (trace.fraction == 1.0)
75                 return false;
76         mid = bottom = trace.endpos[2];
77
78 // the corners must be within 16 of the midpoint
79         for     (x=0 ; x<=1 ; x++)
80                 for     (y=0 ; y<=1 ; y++)
81                 {
82                         start[0] = stop[0] = x ? maxs[0] : mins[0];
83                         start[1] = stop[1] = y ? maxs[1] : mins[1];
84
85                         trace = SV_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent);
86
87                         if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
88                                 bottom = trace.endpos[2];
89                         if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
90                                 return false;
91                 }
92
93         c_yes++;
94         return true;
95 }
96
97
98 /*
99 =============
100 SV_movestep
101
102 Called by monster program code.
103 The move will be adjusted for slopes and stairs, but if the move isn't
104 possible, no move is done, false is returned, and
105 pr_global_struct->trace_normal is set to the normal of the blocking wall
106 =============
107 */
108 qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
109 {
110         float           dz;
111         vec3_t          oldorg, neworg, end, traceendpos;
112         trace_t         trace;
113         int                     i;
114         edict_t         *enemy;
115
116 // try the move
117         VectorCopy (ent->v->origin, oldorg);
118         VectorAdd (ent->v->origin, move, neworg);
119
120 // flying monsters don't step up
121         if ( (int)ent->v->flags & (FL_SWIM | FL_FLY) )
122         {
123         // try one move with vertical motion, then one without
124                 for (i=0 ; i<2 ; i++)
125                 {
126                         VectorAdd (ent->v->origin, move, neworg);
127                         enemy = PROG_TO_EDICT(ent->v->enemy);
128                         if (i == 0 && enemy != sv.edicts)
129                         {
130                                 dz = ent->v->origin[2] - PROG_TO_EDICT(ent->v->enemy)->v->origin[2];
131                                 if (dz > 40)
132                                         neworg[2] -= 8;
133                                 if (dz < 30)
134                                         neworg[2] += 8;
135                         }
136                         trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, neworg, MOVE_NORMAL, ent);
137
138                         if (trace.fraction == 1)
139                         {
140                                 VectorCopy(trace.endpos, traceendpos);
141                                 if ( ((int)ent->v->flags & FL_SWIM) && sv.worldmodel->PointContents(sv.worldmodel, traceendpos) == CONTENTS_EMPTY )
142                                         return false;   // swim monster left water
143
144                                 VectorCopy (traceendpos, ent->v->origin);
145                                 if (relink)
146                                         SV_LinkEdict (ent, true);
147                                 return true;
148                         }
149
150                         if (enemy == sv.edicts)
151                                 break;
152                 }
153
154                 return false;
155         }
156
157 // push down from a step height above the wished position
158         neworg[2] += sv_stepheight.value;
159         VectorCopy (neworg, end);
160         end[2] -= sv_stepheight.value*2;
161
162         trace = SV_Move (neworg, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
163
164         if (trace.allsolid)
165                 return false;
166
167         if (trace.startsolid)
168         {
169                 neworg[2] -= sv_stepheight.value;
170                 trace = SV_Move (neworg, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
171                 if (trace.allsolid || trace.startsolid)
172                         return false;
173         }
174         if (trace.fraction == 1)
175         {
176         // if monster had the ground pulled out, go ahead and fall
177                 if ( (int)ent->v->flags & FL_PARTIALGROUND )
178                 {
179                         VectorAdd (ent->v->origin, move, ent->v->origin);
180                         if (relink)
181                                 SV_LinkEdict (ent, true);
182                         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
183                         return true;
184                 }
185
186                 return false;           // walked off an edge
187         }
188
189 // check point traces down for dangling corners
190         VectorCopy (trace.endpos, ent->v->origin);
191
192         if (!SV_CheckBottom (ent))
193         {
194                 if ( (int)ent->v->flags & FL_PARTIALGROUND )
195                 {       // entity had floor mostly pulled out from underneath it
196                         // and is trying to correct
197                         if (relink)
198                                 SV_LinkEdict (ent, true);
199                         return true;
200                 }
201                 VectorCopy (oldorg, ent->v->origin);
202                 return false;
203         }
204
205         if ( (int)ent->v->flags & FL_PARTIALGROUND )
206                 ent->v->flags = (int)ent->v->flags & ~FL_PARTIALGROUND;
207
208         ent->v->groundentity = EDICT_TO_PROG(trace.ent);
209
210 // the move is ok
211         if (relink)
212                 SV_LinkEdict (ent, true);
213         return true;
214 }
215
216
217 //============================================================================
218
219 /*
220 ======================
221 SV_StepDirection
222
223 Turns to the movement direction, and walks the current distance if
224 facing it.
225
226 ======================
227 */
228 void PF_changeyaw (void);
229 qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
230 {
231         vec3_t          move, oldorigin;
232         float           delta;
233
234         ent->v->ideal_yaw = yaw;
235         PF_changeyaw();
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 */
264 void SV_FixCheckBottom (edict_t *ent)
265 {
266         ent->v->flags = (int)ent->v->flags | FL_PARTIALGROUND;
267 }
268
269
270
271 /*
272 ================
273 SV_NewChaseDir
274
275 ================
276 */
277 #define DI_NODIR        -1
278 void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
279 {
280         float           deltax,deltay;
281         float                   d[3];
282         float           tdir, olddir, turnaround;
283
284         olddir = ANGLEMOD((int)(actor->v->ideal_yaw/45)*45);
285         turnaround = ANGLEMOD(olddir - 180);
286
287         deltax = enemy->v->origin[0] - actor->v->origin[0];
288         deltay = enemy->v->origin[1] - actor->v->origin[1];
289         if (deltax>10)
290                 d[1]= 0;
291         else if (deltax<-10)
292                 d[1]= 180;
293         else
294                 d[1]= DI_NODIR;
295         if (deltay<-10)
296                 d[2]= 270;
297         else if (deltay>10)
298                 d[2]= 90;
299         else
300                 d[2]= DI_NODIR;
301
302 // try direct route
303         if (d[1] != DI_NODIR && d[2] != DI_NODIR)
304         {
305                 if (d[1] == 0)
306                         tdir = d[2] == 90 ? 45 : 315;
307                 else
308                         tdir = d[2] == 90 ? 135 : 215;
309
310                 if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
311                         return;
312         }
313
314 // try other directions
315         if ( ((rand()&3) & 1) ||  abs(deltay)>abs(deltax))
316         {
317                 tdir=d[1];
318                 d[1]=d[2];
319                 d[2]=tdir;
320         }
321
322         if (d[1]!=DI_NODIR && d[1]!=turnaround
323         && SV_StepDirection(actor, d[1], dist))
324                         return;
325
326         if (d[2]!=DI_NODIR && d[2]!=turnaround
327         && 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 */
367 qboolean 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 void SV_MoveToGoal (void)
388 {
389         edict_t         *ent, *goal;
390         float           dist;
391
392         ent = PROG_TO_EDICT(pr_global_struct->self);
393         goal = PROG_TO_EDICT(ent->v->goalentity);
394         dist = G_FLOAT(OFS_PARM0);
395
396         if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
397         {
398                 G_FLOAT(OFS_RETURN) = 0;
399                 return;
400         }
401
402 // if the next step hits the enemy, return immediately
403         if ( PROG_TO_EDICT(ent->v->enemy) != sv.edicts &&  SV_CloseEnough (ent, goal, dist) )
404                 return;
405
406 // bump around...
407         if ( (rand()&3)==1 ||
408         !SV_StepDirection (ent, ent->v->ideal_yaw, dist))
409         {
410                 SV_NewChaseDir (ent, goal, dist);
411         }
412 }
413