Home | History | Annotate | Download | only in WinQuake
      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->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 */
    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);
    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 */
    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
    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 */
    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 */
    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