• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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