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