541 lines · 10.6 KB · C
RawDownload
// m_move.c -- monster movement #include <u.h>#include <libc.h>#include <stdio.h>#include "../dat.h"#include "../fns.h" #define	STEPSIZE	18 /*=============M_CheckBottom Returns false if any part of the bottom of the entity is off an edge thatis not a staircase. =============*/int c_yes, c_no; qboolean M_CheckBottom (edict_t *ent){	vec3_t	mins, maxs, start, stop;	trace_t	trace;	int		x, y;	float	mid, bottom;		VectorAdd (ent->s.origin, ent->mins, mins);	VectorAdd (ent->s.origin, ent->maxs, maxs); // if all of the points under the corners are solid world, don't bother// with the tougher checks// the corners must be within 16 of the midpoint	start[2] = mins[2] - 1;	for	(x=0 ; x<=1 ; x++)		for	(y=0 ; y<=1 ; y++)		{			start[0] = x ? maxs[0] : mins[0];			start[1] = y ? maxs[1] : mins[1];			if (gi.pointcontents (start) != CONTENTS_SOLID)				goto realcheck;		} 	c_yes++;	return true;		// we got out easy realcheck:	c_no++;//// check it for real...//	start[2] = mins[2];	// the midpoint must be within 16 of the bottom	start[0] = stop[0] = (mins[0] + maxs[0])*0.5;	start[1] = stop[1] = (mins[1] + maxs[1])*0.5;	stop[2] = start[2] - 2*STEPSIZE;	trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID); 	if (trace.fraction == 1.0)		return false;	mid = bottom = trace.endpos[2];	// the corners must be within 16 of the midpoint		for	(x=0 ; x<=1 ; x++)		for	(y=0 ; y<=1 ; y++)		{			start[0] = stop[0] = x ? maxs[0] : mins[0];			start[1] = stop[1] = y ? maxs[1] : mins[1];						trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);						if (trace.fraction != 1.0 && trace.endpos[2] > bottom)				bottom = trace.endpos[2];			if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)				return false;		} 	c_yes++;	return true;}  /*=============SV_movestep Called by monster program code.The move will be adjusted for slopes and stairs, but if the move isn'tpossible, no move is done, false is returned, andpr_global_struct->trace_normal is set to the normal of the blocking wall=============*///FIXME since we need to test end position contents here, can we avoid doing//it again later in catagorize position?qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink){	float		dz;	vec3_t		oldorg, neworg, end;	trace_t		trace;	int			i;	float		stepsize;	vec3_t		test;	int			contents; // try the move		VectorCopy (ent->s.origin, oldorg);	VectorAdd (ent->s.origin, move, neworg); // flying monsters don't step up	if ( ent->flags & (FL_SWIM | FL_FLY) )	{	// try one move with vertical motion, then one without		for (i=0 ; i<2 ; i++)		{			VectorAdd (ent->s.origin, move, neworg);			if (i == 0 && ent->enemy)			{				if (!ent->goalentity)					ent->goalentity = ent->enemy;				dz = ent->s.origin[2] - ent->goalentity->s.origin[2];				if (ent->goalentity->client)				{					if (dz > 40)						neworg[2] -= 8;					if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))						if (dz < 30)							neworg[2] += 8;				}				else				{					if (dz > 8)						neworg[2] -= 8;					else if (dz > 0)						neworg[2] -= dz;					else if (dz < -8)						neworg[2] += 8;					else						neworg[2] += dz;				}			}			trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID);				// fly monsters don't enter water voluntarily			if (ent->flags & FL_FLY)			{				if (!ent->waterlevel)				{					test[0] = trace.endpos[0];					test[1] = trace.endpos[1];					test[2] = trace.endpos[2] + ent->mins[2] + 1;					contents = gi.pointcontents(test);					if (contents & MASK_WATER)						return false;				}			} 			// swim monsters don't exit water voluntarily			if (ent->flags & FL_SWIM)			{				if (ent->waterlevel < 2)				{					test[0] = trace.endpos[0];					test[1] = trace.endpos[1];					test[2] = trace.endpos[2] + ent->mins[2] + 1;					contents = gi.pointcontents(test);					if (!(contents & MASK_WATER))						return false;				}			} 			if (trace.fraction == 1)			{				VectorCopy (trace.endpos, ent->s.origin);				if (relink)				{					gi.linkentity (ent);					G_TouchTriggers (ent);				}				return true;			}						if (!ent->enemy)				break;		}				return false;	} // push down from a step height above the wished position	if (!(ent->monsterinfo.aiflags & AI_NOSTEP))		stepsize = STEPSIZE;	else		stepsize = 1; 	neworg[2] += stepsize;	VectorCopy (neworg, end);	end[2] -= stepsize*2; 	trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); 	if (trace.allsolid)		return false; 	if (trace.startsolid)	{		neworg[2] -= stepsize;		trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);		if (trace.allsolid || trace.startsolid)			return false;	}  	// don't go in to water	if (ent->waterlevel == 0)	{		test[0] = trace.endpos[0];		test[1] = trace.endpos[1];		test[2] = trace.endpos[2] + ent->mins[2] + 1;			contents = gi.pointcontents(test); 		if (contents & MASK_WATER)			return false;	} 	if (trace.fraction == 1)	{	// if monster had the ground pulled out, go ahead and fall		if ( ent->flags & FL_PARTIALGROUND )		{			VectorAdd (ent->s.origin, move, ent->s.origin);			if (relink)			{				gi.linkentity (ent);				G_TouchTriggers (ent);			}			ent->groundentity = NULL;			return true;		}			return false;		// walked off an edge	} // check point traces down for dangling corners	VectorCopy (trace.endpos, ent->s.origin);		if (!M_CheckBottom (ent))	{		if ( ent->flags & FL_PARTIALGROUND )		{	// entity had floor mostly pulled out from underneath it			// and is trying to correct			if (relink)			{				gi.linkentity (ent);				G_TouchTriggers (ent);			}			return true;		}		VectorCopy (oldorg, ent->s.origin);		return false;	} 	if ( ent->flags & FL_PARTIALGROUND )	{		ent->flags &= ~FL_PARTIALGROUND;	}	ent->groundentity = trace.ent;	ent->groundentity_linkcount = trace.ent->linkcount; // the move is ok	if (relink)	{		gi.linkentity (ent);		G_TouchTriggers (ent);	}	return true;}  //============================================================================ /*===============M_ChangeYaw ===============*/void M_ChangeYaw (edict_t *ent){	float	ideal;	float	current;	float	move;	float	speed;		current = anglemod(ent->s.angles[YAW]);	ideal = ent->ideal_yaw; 	if (current == ideal)		return; 	move = ideal - current;	speed = ent->yaw_speed;	if (ideal > current)	{		if (move >= 180)			move = move - 360;	}	else	{		if (move <= -180)			move = move + 360;	}	if (move > 0)	{		if (move > speed)			move = speed;	}	else	{		if (move < -speed)			move = -speed;	}		ent->s.angles[YAW] = anglemod (current + move);}  /*======================SV_StepDirection Turns to the movement direction, and walks the current distance iffacing it. ======================*/qboolean SV_StepDirection (edict_t *ent, float yaw, float dist){	vec3_t		move, oldorigin;	float		delta;		ent->ideal_yaw = yaw;	M_ChangeYaw (ent);		yaw = yaw*M_PI*2 / 360;	move[0] = cos(yaw)*dist;	move[1] = sin(yaw)*dist;	move[2] = 0; 	VectorCopy (ent->s.origin, oldorigin);	if (SV_movestep (ent, move, false))	{		delta = ent->s.angles[YAW] - ent->ideal_yaw;		if (delta > 45 && delta < 315)		{		// not turned far enough, so don't take the step			VectorCopy (oldorigin, ent->s.origin);		}		gi.linkentity (ent);		G_TouchTriggers (ent);		return true;	}	gi.linkentity (ent);	G_TouchTriggers (ent);	return false;} /*======================SV_FixCheckBottom ======================*/void SV_FixCheckBottom (edict_t *ent){	ent->flags |= FL_PARTIALGROUND;}   /*================SV_NewChaseDir ================*/#define	DI_NODIR	-1void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist){	float	deltax,deltay;	float	d[3];	float	tdir, olddir, turnaround; 	//FIXME: how did we get here with no enemy	if (!enemy)		return; 	olddir = anglemod( (int)(actor->ideal_yaw/45)*45 );	turnaround = anglemod(olddir - 180); 	deltax = enemy->s.origin[0] - actor->s.origin[0];	deltay = enemy->s.origin[1] - actor->s.origin[1];	if (deltax>10)		d[1]= 0;	else if (deltax<-10)		d[1]= 180;	else		d[1]= DI_NODIR;	if (deltay<-10)		d[2]= 270;	else if (deltay>10)		d[2]= 90;	else		d[2]= DI_NODIR; // try direct route	if (d[1] != DI_NODIR && d[2] != DI_NODIR)	{		if (d[1] == 0)			tdir = d[2] == 90 ? 45 : 315;		else			tdir = d[2] == 90 ? 135 : 215;					if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))			return;	} // try other directions	if ( ((rand()&3) & 1) ||  abs(deltay)>abs(deltax))	{		tdir=d[1];		d[1]=d[2];		d[2]=tdir;	} 	if (d[1]!=DI_NODIR && d[1]!=turnaround 	&& SV_StepDirection(actor, d[1], dist))			return; 	if (d[2]!=DI_NODIR && d[2]!=turnaround	&& SV_StepDirection(actor, d[2], dist))			return; /* there is no direct path to the player, so pick another direction */ 	if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))			return; 	if (rand()&1) 	/*randomly determine direction of search*/	{		for (tdir=0 ; tdir<=315 ; tdir += 45)			if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )					return;	}	else	{		for (tdir=315 ; tdir >=0 ; tdir -= 45)			if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )					return;	} 	if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )			return; 	actor->ideal_yaw = olddir;		// can't move // if a bridge was pulled out from underneath a monster, it may not have// a valid standing position at all 	if (!M_CheckBottom (actor))		SV_FixCheckBottom (actor);} /*======================SV_CloseEnough ======================*/qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist){	int		i;		for (i=0 ; i<3 ; i++)	{		if (goal->absmin[i] > ent->absmax[i] + dist)			return false;		if (goal->absmax[i] < ent->absmin[i] - dist)			return false;	}	return true;}  /*======================M_MoveToGoal======================*/void M_MoveToGoal (edict_t *ent, float dist)

Lines 1–500 of 541.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t