added a bunch more COLLISIONPARANOID code trying to track down a physics bug with...
[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_PointSuperContents(start) & SUPERCONTENTS_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 #if COLLISIONPARANOID >= 1
138         {
139                 int endstuck;
140                 vec3_t temp;
141                 VectorCopy(trace.endpos, temp);
142                 endstuck = SV_Move(temp, ent->v->mins, ent->v->maxs, temp, MOVE_WORLDONLY, ent).startsolid;
143 #if COLLISIONPARANOID < 2
144                 if (trace.startsolid || endstuck)
145 #endif
146                 {
147                         Con_Printf("%s{e%i:%f %f %f:%f %f %f:%f:%f %f %f%s%s}\n", (trace.startsolid || endstuck) ? "\002" : "", ent - sv.edicts, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2], end[0] - ent->v->origin[0], end[1] - ent->v->origin[1], end[2] - ent->v->origin[2], trace.fraction, trace.endpos[0] - ent->v->origin[0], trace.endpos[1] - ent->v->origin[1], trace.endpos[2] - ent->v->origin[2], trace.startsolid ? " startstuck" : "", endstuck ? " endstuck" : "");
148                         //Con_Printf("trace %f %f %f : %f : %f %f %f\n", trace.endpos[0], trace.endpos[1], trace.endpos[2], trace.fraction, trace.plane.normal[0], trace.plane.normal[1], trace.plane.normal[2]);
149                         if (endstuck)
150                                 Cbuf_AddText("disconnect\n");
151                 }
152         }
153 #endif
154
155                         if (trace.fraction == 1)
156                         {
157                                 VectorCopy(trace.endpos, traceendpos);
158                                 if (((int)ent->v->flags & FL_SWIM) && !(SV_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
159                                         return false;   // swim monster left water
160
161                                 VectorCopy (traceendpos, ent->v->origin);
162                                 if (relink)
163                                         SV_LinkEdict (ent, true);
164                                 return true;
165                         }
166
167                         if (enemy == sv.edicts)
168                                 break;
169                 }
170
171                 return false;
172         }
173
174 // push down from a step height above the wished position
175         neworg[2] += sv_stepheight.value;
176         VectorCopy (neworg, end);
177         end[2] -= sv_stepheight.value*2;
178
179         trace = SV_Move (neworg, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
180
181         if (trace.startsolid)
182         {
183                 neworg[2] -= sv_stepheight.value;
184                 trace = SV_Move (neworg, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
185                 if (trace.startsolid)
186                         return false;
187         }
188         if (trace.fraction == 1)
189         {
190         // if monster had the ground pulled out, go ahead and fall
191                 if ( (int)ent->v->flags & FL_PARTIALGROUND )
192                 {
193                         VectorAdd (ent->v->origin, move, ent->v->origin);
194                         if (relink)
195                                 SV_LinkEdict (ent, true);
196                         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
197                         return true;
198                 }
199
200                 return false;           // walked off an edge
201         }
202
203 // check point traces down for dangling corners
204         VectorCopy (trace.endpos, ent->v->origin);
205
206         if (!SV_CheckBottom (ent))
207         {
208                 if ( (int)ent->v->flags & FL_PARTIALGROUND )
209                 {       // entity had floor mostly pulled out from underneath it
210                         // and is trying to correct
211                         if (relink)
212                                 SV_LinkEdict (ent, true);
213                         return true;
214                 }
215                 VectorCopy (oldorg, ent->v->origin);
216                 return false;
217         }
218
219         if ( (int)ent->v->flags & FL_PARTIALGROUND )
220                 ent->v->flags = (int)ent->v->flags & ~FL_PARTIALGROUND;
221
222         ent->v->groundentity = EDICT_TO_PROG(trace.ent);
223
224 // the move is ok
225         if (relink)
226                 SV_LinkEdict (ent, true);
227         return true;
228 }
229
230
231 //============================================================================
232
233 /*
234 ======================
235 SV_StepDirection
236
237 Turns to the movement direction, and walks the current distance if
238 facing it.
239
240 ======================
241 */
242 void PF_changeyaw (void);
243 qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
244 {
245         vec3_t          move, oldorigin;
246         float           delta;
247
248         ent->v->ideal_yaw = yaw;
249         PF_changeyaw();
250
251         yaw = yaw*M_PI*2 / 360;
252         move[0] = cos(yaw)*dist;
253         move[1] = sin(yaw)*dist;
254         move[2] = 0;
255
256         VectorCopy (ent->v->origin, oldorigin);
257         if (SV_movestep (ent, move, false))
258         {
259                 delta = ent->v->angles[YAW] - ent->v->ideal_yaw;
260                 if (delta > 45 && delta < 315)
261                 {               // not turned far enough, so don't take the step
262                         VectorCopy (oldorigin, ent->v->origin);
263                 }
264                 SV_LinkEdict (ent, true);
265                 return true;
266         }
267         SV_LinkEdict (ent, true);
268
269         return false;
270 }
271
272 /*
273 ======================
274 SV_FixCheckBottom
275
276 ======================
277 */
278 void SV_FixCheckBottom (edict_t *ent)
279 {
280         ent->v->flags = (int)ent->v->flags | FL_PARTIALGROUND;
281 }
282
283
284
285 /*
286 ================
287 SV_NewChaseDir
288
289 ================
290 */
291 #define DI_NODIR        -1
292 void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
293 {
294         float           deltax,deltay;
295         float                   d[3];
296         float           tdir, olddir, turnaround;
297
298         olddir = ANGLEMOD((int)(actor->v->ideal_yaw/45)*45);
299         turnaround = ANGLEMOD(olddir - 180);
300
301         deltax = enemy->v->origin[0] - actor->v->origin[0];
302         deltay = enemy->v->origin[1] - actor->v->origin[1];
303         if (deltax>10)
304                 d[1]= 0;
305         else if (deltax<-10)
306                 d[1]= 180;
307         else
308                 d[1]= DI_NODIR;
309         if (deltay<-10)
310                 d[2]= 270;
311         else if (deltay>10)
312                 d[2]= 90;
313         else
314                 d[2]= DI_NODIR;
315
316 // try direct route
317         if (d[1] != DI_NODIR && d[2] != DI_NODIR)
318         {
319                 if (d[1] == 0)
320                         tdir = d[2] == 90 ? 45 : 315;
321                 else
322                         tdir = d[2] == 90 ? 135 : 215;
323
324                 if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
325                         return;
326         }
327
328 // try other directions
329         if ( ((rand()&3) & 1) ||  abs(deltay)>abs(deltax))
330         {
331                 tdir=d[1];
332                 d[1]=d[2];
333                 d[2]=tdir;
334         }
335
336         if (d[1]!=DI_NODIR && d[1]!=turnaround
337         && SV_StepDirection(actor, d[1], dist))
338                         return;
339
340         if (d[2]!=DI_NODIR && d[2]!=turnaround
341         && SV_StepDirection(actor, d[2], dist))
342                         return;
343
344 /* there is no direct path to the player, so pick another direction */
345
346         if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
347                         return;
348
349         if (rand()&1)   /*randomly determine direction of search*/
350         {
351                 for (tdir=0 ; tdir<=315 ; tdir += 45)
352                         if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
353                                         return;
354         }
355         else
356         {
357                 for (tdir=315 ; tdir >=0 ; tdir -= 45)
358                         if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
359                                         return;
360         }
361
362         if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
363                         return;
364
365         actor->v->ideal_yaw = olddir;           // can't move
366
367 // if a bridge was pulled out from underneath a monster, it may not have
368 // a valid standing position at all
369
370         if (!SV_CheckBottom (actor))
371                 SV_FixCheckBottom (actor);
372
373 }
374
375 /*
376 ======================
377 SV_CloseEnough
378
379 ======================
380 */
381 qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
382 {
383         int             i;
384
385         for (i=0 ; i<3 ; i++)
386         {
387                 if (goal->v->absmin[i] > ent->v->absmax[i] + dist)
388                         return false;
389                 if (goal->v->absmax[i] < ent->v->absmin[i] - dist)
390                         return false;
391         }
392         return true;
393 }
394
395 /*
396 ======================
397 SV_MoveToGoal
398
399 ======================
400 */
401 void SV_MoveToGoal (void)
402 {
403         edict_t         *ent, *goal;
404         float           dist;
405
406         ent = PROG_TO_EDICT(pr_global_struct->self);
407         goal = PROG_TO_EDICT(ent->v->goalentity);
408         dist = G_FLOAT(OFS_PARM0);
409
410         if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
411         {
412                 G_FLOAT(OFS_RETURN) = 0;
413                 return;
414         }
415
416 // if the next step hits the enemy, return immediately
417         if ( PROG_TO_EDICT(ent->v->enemy) != sv.edicts &&  SV_CloseEnough (ent, goal, dist) )
418                 return;
419
420 // bump around...
421         if ( (rand()&3)==1 ||
422         !SV_StepDirection (ent, ent->v->ideal_yaw, dist))
423         {
424                 SV_NewChaseDir (ent, goal, dist);
425         }
426 }
427