1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20// sv_move.c -- monster movement
21
22#include "qwsvdef.h"
23
24#define	STEPSIZE	18
25
26/*
27=============
28SV_CheckBottom
29
30Returns false if any part of the bottom of the entity is off an edge that
31is not a staircase.
32
33=============
34*/
35int c_yes, c_no;
36
37qboolean 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
60	c_yes++;
61	return true;		// we got out easy
62
63realcheck:
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=============
102SV_movestep
103
104Called by monster program code.
105The move will be adjusted for slopes and stairs, but if the move isn't
106possible, no move is done, false is returned, and
107pr_global_struct->trace_normal is set to the normal of the blocking wall
108=============
109*/
110qboolean 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->v.origin, oldorg);
120	VectorAdd (ent->v.origin, move, neworg);
121
122// flying monsters don't step up
123	if ( (int)ent->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->v.origin, move, neworg);
129			enemy = PROG_TO_EDICT(ent->v.enemy);
130			if (i == 0 && enemy != sv.edicts)
131			{
132				dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->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->v.origin, ent->v.mins, ent->v.maxs, neworg, false, ent);
139
140			if (trace.fraction == 1)
141			{
142				if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY )
143					return false;	// swim monster left water
144
145				VectorCopy (trace.endpos, ent->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->v.mins, ent->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->v.mins, ent->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->v.flags & FL_PARTIALGROUND )
179		{
180			VectorAdd (ent->v.origin, move, ent->v.origin);
181			if (relink)
182				SV_LinkEdict (ent, true);
183			ent->v.flags = (int)ent->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->v.origin);
193
194	if (!SV_CheckBottom (ent))
195	{
196		if ( (int)ent->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->v.origin);
204		return false;
205	}
206
207	if ( (int)ent->v.flags & FL_PARTIALGROUND )
208	{
209//		Con_Printf ("back on ground\n");
210		ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND;
211	}
212	ent->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======================
225SV_StepDirection
226
227Turns to the movement direction, and walks the current distance if
228facing it.
229
230======================
231*/
232void PF_changeyaw (void);
233qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
234{
235	vec3_t		move, oldorigin;
236	float		delta;
237
238	ent->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->v.origin, oldorigin);
247	if (SV_movestep (ent, move, false))
248	{
249		delta = ent->v.angles[YAW] - ent->v.ideal_yaw;
250		if (delta > 45 && delta < 315)
251		{		// not turned far enough, so don't take the step
252			VectorCopy (oldorigin, ent->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======================
264SV_FixCheckBottom
265
266======================
267*/
268void SV_FixCheckBottom (edict_t *ent)
269{
270//	Con_Printf ("SV_FixCheckBottom\n");
271
272	ent->v.flags = (int)ent->v.flags | FL_PARTIALGROUND;
273}
274
275
276
277/*
278================
279SV_NewChaseDir
280
281================
282*/
283#define	DI_NODIR	-1
284void 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->v.ideal_yaw/45)*45 );
291	turnaround = anglemod(olddir - 180);
292
293	deltax = enemy->v.origin[0] - actor->v.origin[0];
294	deltay = enemy->v.origin[1] - actor->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(deltay)>abs(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->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======================
369SV_CloseEnough
370
371======================
372*/
373qboolean 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->v.absmin[i] > ent->v.absmax[i] + dist)
380			return false;
381		if (goal->v.absmax[i] < ent->v.absmin[i] - dist)
382			return false;
383	}
384	return true;
385}
386
387/*
388======================
389SV_MoveToGoal
390
391======================
392*/
393void SV_MoveToGoal (void)
394{
395	edict_t		*ent, *goal;
396	float		dist;
397
398	ent = PROG_TO_EDICT(pr_global_struct->self);
399	goal = PROG_TO_EDICT(ent->v.goalentity);
400	dist = G_FLOAT(OFS_PARM0);
401
402	if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
403	{
404		G_FLOAT(OFS_RETURN) = 0;
405		return;
406	}
407
408// if the next step hits the enemy, return immediately
409	if ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts &&  SV_CloseEnough (ent, goal, dist) )
410		return;
411
412// bump around...
413	if ( (rand()&3)==1 ||
414	!SV_StepDirection (ent, ent->v.ideal_yaw, dist))
415	{
416		SV_NewChaseDir (ent, goal, dist);
417	}
418}
419
420