Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 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
 
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->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
 
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
*/
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->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
======================
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);
233
qboolean 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
======================
264
SV_FixCheckBottom
265
 
266
======================
267
*/
268
void 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
================
279
SV_NewChaseDir
280
 
281
================
282
*/
283
#define	DI_NODIR	-1
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->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
======================
369
SV_CloseEnough
370
 
371
======================
372
*/
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->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
======================
389
SV_MoveToGoal
390
 
391
======================
392
*/
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->v.goalentity);
403
	dist = G_FLOAT(OFS_PARM0);
404
 
405
	if ( !( (int)ent->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->v.enemy);
414
	if (enemy != sv.edicts &&  SV_CloseEnough (ent, enemy, dist) )
415
#else
416
	if ( PROG_TO_EDICT(ent->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->v.ideal_yaw, dist))
423
	{
424
		SV_NewChaseDir (ent, goal, dist);
425
	}
426
}
427