Пример #1
0
void
mutant_jump_touch(edict_t *self, edict_t *other, cplane_t *plane /* unused */,
		csurface_t *surf /* unused */)
{
	if (!self || !other)
	{
		return;
	}

	if (self->health <= 0)
	{
		self->touch = NULL;
		return;
	}

	if (other->takedamage)
	{
		if (VectorLength(self->velocity) > 400)
		{
			vec3_t point;
			vec3_t normal;
			int damage;

			VectorCopy(self->velocity, normal);
			VectorNormalize(normal);
			VectorMA(self->s.origin, self->maxs[0], normal, point);
			damage = 40 + 10 * random();
			T_Damage(other, self, self, self->velocity, point,
					normal, damage, damage, 0, MOD_UNKNOWN);
		}
	}

	if (!M_CheckBottom(self))
	{
		if (self->groundentity)
		{
			self->monsterinfo.nextframe = FRAME_attack02;
			self->touch = NULL;
		}

		return;
	}

	self->touch = NULL;
}
Пример #2
0
void gekk_jump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
	if (self->health <= 0)
	{
		self->touch = NULL;
		return;
	}

	if (other->takedamage)
	{
		if (VectorLength(self->velocity) > 200)
		{
			vec3_t	point;
			vec3_t	normal;
			int		damage;

			VectorCopy (self->velocity, normal);
			VectorNormalize(normal);
			VectorMA (self->s.origin, self->maxs[0], normal, point);
			damage = 10 + 10 * random();
			T_Damage (other, self, self, self->velocity, point, normal, damage, damage, 0, MOD_GEKK);
		}
	}

	if (!M_CheckBottom (self))
	{
		if (self->groundentity)
		{
			self->monsterinfo.nextframe = FRAME_leapatk_11;
			self->touch = NULL;
		}
		return;
	}

	self->touch = NULL;
}
Пример #3
0
void SV_Physics_Step (edict_t *ent)
{
	qboolean	wasonground;
	qboolean	hitsound = false;
	float		*vel;
	float		speed, newspeed, control;
	float		friction;
	edict_t		*groundentity;
	int			mask;

	// airborn monsters should always check for ground
	if (!ent->groundentity)
		M_CheckGround (ent);

	groundentity = ent->groundentity;

	SV_CheckVelocity (ent);

	if (groundentity)
		wasonground = true;
	else
		wasonground = false;
		
	if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
		SV_AddRotationalFriction (ent);

	// add gravity except:
	//   flying monsters
	//   swimming monsters who are in the water
	if (! wasonground)
		if (!(ent->flags & FL_FLY))
			if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
			{
				if (ent->velocity[2] < sv_gravity->value*-0.1)
					hitsound = true;
				if (ent->waterlevel == 0)
					SV_AddGravity (ent);
			}

	// friction for flying monsters that have been given vertical velocity
	if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
	{
		speed = fabs(ent->velocity[2]);
		control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed;
		friction = sv_friction/3;
		newspeed = speed - (FRAMETIME * control * friction);
		if (newspeed < 0)
			newspeed = 0;
		newspeed /= speed;
		ent->velocity[2] *= newspeed;
	}

	// friction for flying monsters that have been given vertical velocity
	if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
	{
		speed = fabs(ent->velocity[2]);
		control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed;
		newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
		if (newspeed < 0)
			newspeed = 0;
		newspeed /= speed;
		ent->velocity[2] *= newspeed;
	}

	if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
	{
		// apply friction
		// let dead monsters who aren't completely onground slide
		if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
			if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
			{
				vel = ent->velocity;
				speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
				if (speed)
				{
					friction = sv_friction;

					control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed;
					newspeed = speed - FRAMETIME*control*friction;

					if (newspeed < 0)
						newspeed = 0;
					newspeed /= speed;

					vel[0] *= newspeed;
					vel[1] *= newspeed;
				}
			}

		if (ent->svflags & SVF_MONSTER)
			mask = MASK_MONSTERSOLID;
		else
			mask = MASK_SOLID;
		SV_FlyMove (ent, FRAMETIME, mask);

		gi.linkentity (ent);

// ========
// PGM - reset this every time they move. 
//       G_touchtriggers will set it back if appropriate
		ent->gravity = 1.0;
// ========
		
		G_TouchTriggers (ent);
		if (!ent->inuse)
			return;

		if (ent->groundentity)
			if (!wasonground)
				if (hitsound)
					gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
	}

	if(!ent->inuse)			// PGM g_touchtrigger free problem
		return;

// regular thinking
	SV_RunThink (ent);
}
Пример #4
0
void 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);
}
Пример #5
0
//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;

// BEGIN:	Xatrix/Ridah/Navigator/14-apr-1998
	int			mask = MASK_MONSTERSOLID;

	if (ent->cast_info.aiflags & AI_PLAYERCLIP)
		mask = MASK_PLAYERSOLID;
	else if (ent->flags & FL_RESPAWN)	// used for moveout command
		mask = MASK_SOLID;
// END:		Xatrix/Ridah/Navigator/14-apr-1998

// 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;
					
				}
			}
			
// BEGIN:	Xatrix/Ridah/Navigator/14-apr-1998		(use modified mask for Grunts)
			trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, mask);
// END:		Xatrix/Ridah/Navigator/14-apr-1998

			// 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->cast_info.aiflags & AI_NOSTEP))
		stepsize = STEPSIZE;
	else
		stepsize = 1;

// BEGIN: Xatrix/Ridah/Navigator/03-apr-1998
	if (ent->nav_data.goal_index && ((level.node_data->nodes[ent->nav_data.goal_index-1]->origin[2] - ent->s.origin[2]) > 0))
	{
		stepsize += 8;

		if (ent->waterlevel > 2)
			stepsize = 1;
	}
// END:   Xatrix/Ridah/Navigator/03-apr-1998

	neworg[2] += stepsize;
	VectorCopy (neworg, end);
	end[2] -= stepsize*2;

	trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, mask);

	// Ridah, tell this ent to avoid us if possible
	if ((trace.ent && trace.ent->svflags & SVF_MONSTER) && (ent->health > 0))	// Ridah, Fixes life after death bug
	{
		extern void AI_GetAvoidDirection( edict_t *self, edict_t *other );

		AI_GetAvoidDirection( trace.ent, ent );
		ent->cast_info.currentmove = ent->cast_info.move_avoid_walk;
	}

	if (trace.allsolid)
		return false;

	if (trace.startsolid)
	{
		neworg[2] -= stepsize;
		trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, mask);
		if (trace.allsolid || trace.startsolid || trace.fraction == 0)
		{
			return false;
		}
	}

// BEGIN:	Xatrix/Ridah/Navigator/03-apr-1998
	// don't let monsters walk onto other monsters
	if ((trace.fraction < 1) && (trace.ent->svflags & SVF_MONSTER))
	{
		return false;
	}
// END:		Xatrix/Ridah/Navigator/03-apr-1998

	// don't go in to lava/slime
	if (ent->waterlevel < 2)
	{
		test[0] = trace.endpos[0];
		test[1] = trace.endpos[1];
		test[2] = trace.endpos[2] + ent->mins[2] + 16;
		contents = gi.pointcontents(test);

		if (contents & (CONTENTS_LAVA|CONTENTS_SLIME))
			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;
		}
// BEGIN: Xatrix/Ridah/Navigator/14-apr-1998
		else
		{
			float fall_dist=0;

			// never fall into water
			VectorCopy(trace.endpos, neworg);
			VectorCopy(neworg, end);
			end[2] -= 2048;

			trace = gi.trace( neworg, ent->mins, ent->maxs, end, ent, mask );

			test[0] = trace.endpos[0];
			test[1] = trace.endpos[1];
			test[2] = trace.endpos[2] + ent->mins[2] + 16;
			contents = gi.pointcontents(test);

			if (contents & MASK_WATER)
				return false;
			

/*
			// let them fall into water if they should be doing so
			if (	ent->waterlevel
				||	(ent->count && level.node_data->nodes[ent->count-1]->waterlevel)
				||	(ent->goalentity && ent->goalentity->waterlevel))
			{
				VectorAdd (ent->s.origin, move, ent->s.origin);
				VectorScale(move, 10, ent->velocity);
				ent->groundentity = NULL;

				return true;
			}
*/

			if (	(ent->nav_data.goal_index && ((fall_dist = level.node_data->nodes[ent->nav_data.goal_index-1]->origin[2] - ent->s.origin[2]) < 0)) 
				||	(ent->goalentity && (( fall_dist = ent->goalentity->s.origin[2] - ent->s.origin[2]) < 0)))
			{
//				VectorCopy(trace.endpos, neworg);
				VectorCopy(neworg, end);
				end[2] += (fall_dist - 48);

				trace = gi.trace( neworg, ent->mins, ent->maxs, end, ent, mask );

				if (trace.fraction < 1)
				{	// start to fall
					VectorAdd (ent->s.origin, move, ent->s.origin);
					VectorScale(move, 5, ent->velocity);
					ent->groundentity = NULL;

					return true;
				}
			}
		}
// END:   Xatrix/Ridah/Navigator/23-mar-1998

		// walked off an edge
		return false;
	}

	// 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;
		}
		
		// Joseph
		if (!ent->fallerflag)
		{	
			// Ridah, don't bother checking all corners
//			VectorCopy (oldorg, ent->s.origin);
//			return false;
		}
		else 
		{
			vec3_t	forward, right, up;
			int speed = 140;
			
			// JOSEPH 7-OCT-98
			// Stop any drag sound
			ent->s.sound = 0;
			
			// Object is falling
			ent->fallingflag = 1;
			// END JOSEPH
			
			// JOSEPH 17-MAY-99
			if (!ent->pullingflag)
			{
				AngleVectors (move, forward, right, up);

				VectorScale (move, speed, ent->velocity);
				VectorMA (ent->velocity, 100, up, ent->velocity);
				ent->movetype = MOVETYPE_TOSS;
			}
			// END JOSEPH

			// JOSEPH 17-MAY-99
			//VectorAdd (ent->s.origin, move, ent->s.origin);
			// END JOSEPH
			if (relink)
			{
				gi.linkentity (ent);
				G_TouchTriggers (ent);
			}
			ent->groundentity = NULL;
			return true;
		}
	}

	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;
}
Пример #6
0
void SV_Physics_Step (edict_t *ent)
{
	qboolean	wasonground;
	qboolean	hitsound = false;
	float		*vel;
	float		speed, newspeed, control;
	float		friction;
	edict_t		*groundentity;
	int			mask;
	int			retval;
	vec3_t		oldpos;

	// BEGIN:	Xatrix/Ridah
	vec3_t	old_vel;
	// END:		Xatrix/Ridah

	// Joseph
	if (ent->fallerflag)
	{
		// Fix if sitting off center
		think_checkedges(ent);
	}
	
	// airborn monsters should always check for ground
	if (!ent->groundentity)
		M_CheckGround (ent);

	groundentity = ent->groundentity;

	SV_CheckVelocity (ent);

	if (groundentity)
		wasonground = true;
	else
		wasonground = false;
		
	if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
		SV_AddRotationalFriction (ent);

	// add gravity except:
	//   flying monsters
	//   swimming monsters who are in the water
	if (! wasonground)
		if (!(ent->flags & FL_FLY))
			if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
			{
				if (ent->velocity[2] < sv_gravity->value*-0.1)
					hitsound = true;
// Ridah, 1-may-99, disabled this to prevent guys getting stuck in water
//				if (ent->waterlevel == 0)
					SV_AddGravity (ent);
			}
/*
	// friction for flying monsters that have been given vertical velocity
	if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
	{
		speed = fabs(ent->velocity[2]);
		control = speed < sv_stopspeed ? sv_stopspeed : speed;
		friction = sv_friction/3;
		newspeed = speed - (FRAMETIME * control * friction);
		if (newspeed < 0)
			newspeed = 0;
		newspeed /= speed;
		ent->velocity[2] *= newspeed;
	}
*/
	// friction for flying monsters that have been given vertical velocity
	if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
	{
		speed = fabs(ent->velocity[2]);
		control = speed < sv_stopspeed ? sv_stopspeed : speed;
		newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
		if (newspeed < 0)
			newspeed = 0;
		newspeed /= speed;
		ent->velocity[2] *= newspeed;
	}

	if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
	{
		// apply friction
		// let dead monsters who aren't completely onground slide
		if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
			if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
			{
				vel = ent->velocity;
				speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
				if (speed)
				{
					friction = sv_friction;

					control = speed < sv_stopspeed ? sv_stopspeed : speed;
					newspeed = speed - FRAMETIME*control*friction;

					if (newspeed < 0)
						newspeed = 0;
					newspeed /= speed;

					vel[0] *= newspeed;
					vel[1] *= newspeed;
				}
			}

		// BEGIN:	Xatrix/Ridah
		// JOSEPH 26-APR-99
		if ((ent->svflags & SVF_MONSTER) || (ent->monsterprop))
		// END JOSEPH
		{
//			if (ent->cast_info.aiflags & AI_PLAYERCLIP)
				mask = MASK_PLAYERSOLID | CONTENTS_MONSTERCLIP;
//			else
//				mask = MASK_MONSTERSOLID;
		}
		else
			mask = MASK_SOLID;

		VectorCopy (ent->velocity, old_vel);
		// END:		Xatrix/Ridah

		VectorCopy (ent->s.origin, oldpos );

		retval = SV_FlyMove (ent, FRAMETIME, mask);

#if 0	// leave this here for now.

		// Ridah, HACK... sometimes they get stuck, we should debug this properly when we get the time
		if (!ValidBoxAtLoc( ent->s.origin, ent->mins, ent->maxs, ent, MASK_SOLID ))
		{	// move back to old position and clear velocity
			int iter=0;

			VectorCopy (oldpos, ent->s.origin);
			VectorClear (ent->velocity);

			// find a good position
			while (!ValidBoxAtLoc( ent->s.origin, ent->mins, ent->maxs, ent, MASK_SOLID ))
			{
				VectorAdd( ent->s.origin, tv((random()-0.5) * 64, (random()-0.5) * 64, (random()-0.5) * 64), ent->s.origin );

				if (++iter > 10)
					break;
			}

//			if (iter <= 4)
//			{	// make sure they're on the ground
//				M_droptofloor( ent );
//			}

			goto exit_vel_check;		// get out of here?
		}
#endif

		// BEGIN:	Xatrix/Ridah
		if (!ent->groundentity || (ent->flags & FL_FLY))
		{
			node_t	*land_node;

			// Ridah, prevent guys getting stuck trying to jump
			if (VectorDistance( ent->s.origin, oldpos ) < 1 && !ent->groundentity && (ent->last_onground < (level.time - 2)))
			{
				ent->velocity[0] = crandom() * 300;
				ent->velocity[1] = crandom() * 300;

				if (ent->velocity[2] < -200)
					ent->velocity[2] = -200;

				ent->velocity[2] += random() * 350;

				ent->nav_data.goal_index = 0;
				ent->last_onground = level.time;
			}

			if (ent->velocity[2] > 80 && retval != 20)
			{	// while rising, maintain XY velocity
				ent->velocity[0] = old_vel[0];
				ent->velocity[1] = old_vel[1];
			}

			// see if we've gone passed the landing position
			if (	!(ent->flags & FL_FLY)
				&&	(retval == -1) && (ent->nav_data.goal_index)
				&&	(land_node = level.node_data->nodes[ent->nav_data.goal_index-1]))
//				&&	(land_node->node_type & NODE_LANDING))
			{
				vec3_t	unit_vel, goal_dir, goal_vec;
				float	vel_scale, dist;

				VectorSubtract( land_node->origin, ent->s.origin, goal_vec );
				goal_vec[2] = 0;
				dist = VectorNormalize2( goal_vec, goal_dir );

				if (dist > 16)
				{

					VectorCopy( ent->velocity, unit_vel );
					unit_vel[2] = 0;
					vel_scale = VectorNormalize( unit_vel );

					if (DotProduct( unit_vel, goal_dir ) < 0.8)
					{	// we've either gone passed, or need some correction
						vec3_t new_pos;
						float	old_z;

						if (VectorLength( goal_vec ) < 40)
						{
							new_pos[0] = land_node->origin[0];
							new_pos[1] = land_node->origin[1];
							new_pos[2] = ent->s.origin[2];

							if (ValidBoxAtLoc( new_pos, ent->mins, ent->maxs, ent, MASK_PLAYERSOLID | MASK_MONSTERSOLID ))
							{	// move there, it's safe, and clear velocity
								VectorCopy( new_pos, ent->s.origin );
								ent->velocity[0] = ent->velocity[1] = 0;

								goto exit_vel_check;
							}
						}

						// we need to adjust our velocity
						if (land_node->origin[2] < (ent->s.origin[2] - 64))
						{
							old_z = ent->velocity[2];
							VectorScale( goal_dir, vel_scale, ent->velocity );
							ent->velocity[2] = old_z;
						}
						
					}

				}
			}	

			if (	(ent->flags & FL_FLY)
				&&	((land_node = level.node_data->nodes[ent->nav_data.goal_index-1]) || ((ent->flags &= ~FL_FLY) && false))
				/*&&	(land_node->node_type & NODE_LANDING)*/)
			{	// if climbing ladder, and we're reached the landing position, stop

				// Ridah, 8-jun-99, make sure dog's don't climb ladders
				if (!ent->gender)
				{
					goto abort_climb;
				}

				if (ent->s.origin[2] > land_node->origin[2])
				{
//gi.dprintf( "-> end of climb\n" );
//					VectorSubtract( land_node->origin, ent->s.origin, ent->velocity );
					AngleVectors( ent->s.angles, ent->velocity, NULL, NULL );
					ent->velocity[2] = 0;
					VectorNormalize( ent->velocity );
					VectorScale( ent->velocity, 96, ent->velocity );

					ent->velocity[2] = 200;

					ent->flags &= ~FL_FLY;
					ent->nav_data.goal_index = 0;		// look for a new node
					ent->nav_data.cache_node = -1;

					if (ent->cast_info.move_end_climb)
						ent->cast_info.currentmove = ent->cast_info.move_end_climb;
				}
				else
				{
					trace_t tr;
					vec3_t	end, goal_vec;

					VectorSubtract( land_node->origin, ent->s.origin, goal_vec );

					ent->velocity[0] = goal_vec[0];
					ent->velocity[1] = goal_vec[1];
					ent->velocity[2] = 120;

					// if another character is above us, abort
					VectorCopy( ent->s.origin, end );
					end[2] += 128;
					tr = gi.trace( ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_PLAYERSOLID | MASK_MONSTERSOLID );
					
					if ((tr.fraction < 1) && (tr.ent->svflags & SVF_MONSTER))
					{

abort_climb:

						AngleVectors( ent->s.angles, goal_vec, NULL, NULL );
						VectorScale( goal_vec, -64, ent->velocity );
						ent->flags &= ~FL_FLY;
						ent->nav_data.goal_index = 0;

						if (ent->cast_info.move_end_climb)
						{
							ent->cast_info.currentmove = ent->cast_info.move_end_climb;
						}
						else if (ent->cast_info.move_jump)
						{
							ent->cast_info.currentmove = ent->cast_info.move_jump;
						}
					}
					else if (ent->s.origin[2] > (land_node->origin[2] - 48))
					{	// we're near the top, stopping climbing anim
//gi.dprintf( "near end of climb\n" );
						if (ent->cast_info.move_end_climb)
							ent->cast_info.currentmove = ent->cast_info.move_end_climb;

						// add some forward momentum
						AngleVectors( ent->s.angles, goal_vec, NULL, NULL );
						VectorMA( ent->velocity, 64, goal_vec, ent->velocity );
					}

				}

			}
		}

exit_vel_check:

		// END:		Xatrix/Ridah

		gi.linkentity (ent);
		G_TouchTriggers (ent);

// Note to Ryan: we can't use this because we are playing specific sounds elsewhere
/*
		if (ent->groundentity)
			if (!wasonground)
				if (hitsound)
					// BEGIN:	Xatrix/Ridah/Navigator/03-apr-1998
					if (!(ent->cast_info.move_run))
					// END:		Xatrix/Ridah/Navigator/03-apr-1998
						gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
*/
	}

// regular thinking
	SV_RunThink (ent);
}
Пример #7
0
//FIXME since we need to test end position contents here, can we avoid doing
//it again later in catagorize position?
bool SV_movestep(edict_t *ent, vec3_t move, bool 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;
}
Пример #8
0
void SV_Physics_Step (edict_t *ent)
{
	bool	wasonground;
	bool	hitsound = false;
	float		*vel;
	float		speed, newspeed, control;
	float		friction;
	edict_t		*groundentity;
	int			mask;

	// airborn monsters should always check for ground
	if (!ent->groundentity)
		M_CheckGround (ent);

	groundentity = ent->groundentity;

	SV_CheckVelocity (ent);

	if (groundentity)
		wasonground = true;
	else
		wasonground = false;

	if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
		SV_AddRotationalFriction (ent);

	// add gravity except:
	//   flying monsters
	//   swimming monsters who are in the water
	if (! wasonground)
		if (!(ent->flags & FL_FLY))
			if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
			{
				if (ent->velocity[2] < level.gravity*-0.1)
					hitsound = true;
				if (ent->waterlevel == 0)
					SV_AddGravity (ent);
			}

	// friction for flying monsters that have been given vertical velocity
	if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
	{
		speed = fabs(ent->velocity[2]);
		control = speed < sv_stopspeed ? sv_stopspeed : speed;
		friction = sv_friction/3;
		newspeed = speed - (FRAMETIME * control * friction);
		if (newspeed < 0)
			newspeed = 0;
		newspeed /= speed;
		ent->velocity[2] *= newspeed;
	}

	// friction for flying monsters that have been given vertical velocity
	if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
	{
		speed = fabs(ent->velocity[2]);
		control = speed < sv_stopspeed ? sv_stopspeed : speed;
		newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
		if (newspeed < 0)
			newspeed = 0;
		newspeed /= speed;
		ent->velocity[2] *= newspeed;
	}

	if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
	{
		// apply friction
		// let dead monsters who aren't completely onground slide
		if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
			if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
			{
				vel = ent->velocity;
				speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
				if (speed)
				{
					friction = sv_friction;

					control = speed < sv_stopspeed ? sv_stopspeed : speed;
					newspeed = speed - FRAMETIME*control*friction;

					if (newspeed < 0)
						newspeed = 0;
					newspeed /= speed;

					vel[0] *= newspeed;
					vel[1] *= newspeed;
				}
			}

		if (ent->r.svflags & SVF_MONSTER)
			mask = MASK_MONSTERSOLID;
		else
			mask = MASK_SOLID;
		SV_FlyMove (ent, FRAMETIME, mask);

		GClip_LinkEntity (ent);
		GClip_TouchTriggers (ent);

		if (ent->groundentity)
			if (!wasonground)
				if (hitsound)
					G_Sound (ent, 0, trap_SoundIndex( S_LAND ), ATTN_NORM);
	}
}
Пример #9
0
//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;
    edict_t		*current_bad;		// PGM
    float		minheight;			// pmm

//======
//PGM
    current_bad = CheckForBadArea(ent);
    if(current_bad)
    {
//		gi.dprintf("in bad area\n");
        ent->bad_area = current_bad;

        if(ent->enemy && !strcmp(ent->enemy->classname, "tesla"))
        {
//			gi.dprintf("%s  -->>  ", vtos(move));
            VectorScale(move, -1, move);
//			gi.dprintf("%s\n", vtos(move));
        }
    }
    else if(ent->bad_area)
    {
        // if we're no longer in a bad area, get back to business.
        ent->bad_area = NULL;
        if(ent->oldenemy)// && ent->bad_area->owner == ent->enemy)
        {
//			gi.dprintf("resuming being pissed at %s\n", ent->oldenemy->classname);
            ent->enemy = ent->oldenemy;
            ent->goalentity = ent->oldenemy;
            FoundTarget(ent);
            return true;
        }
    }
//PGM
//======

// 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)
                {
                    // we want the carrier to stay a certain distance off the ground, to help prevent him
                    // from shooting his fliers, who spawn in below him
                    //
                    if (!strcmp(ent->classname, "monster_carrier"))
                        minheight = 104;
                    else
                        minheight = 40;
//					if (dz > 40)
                    if (dz > minheight)
//	pmm
                        neworg[2] -= 8;
                    if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))
                        if (dz < (minheight - 10))
                            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)

            // PMM - changed above to this
            if ((trace.fraction == 1) && (!trace.allsolid) && (!trace.startsolid))
            {
                VectorCopy (trace.endpos, ent->s.origin);
//=====
//PGM
                if(!current_bad && CheckForBadArea(ent))
                {
//						gi.dprintf("Oooh! Bad Area!\n");
                    VectorCopy (oldorg, ent->s.origin);
                }
                else
                {
                    if (relink)
                    {
                        gi.linkentity (ent);
                        G_TouchTriggers (ent);
                    }
                    return true;
                }
//PGM
//=====
            }

            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;

//PGM
#ifdef ROGUE_GRAVITY
    // trace from 1 stepsize gravityUp to 2 stepsize gravityDown.
    VectorMA(neworg, -1 * stepsize, ent->gravityVector, neworg);
    VectorMA(neworg, 2 * stepsize, ent->gravityVector, end);
#else
    neworg[2] += stepsize;
    VectorCopy (neworg, end);
    end[2] -= stepsize*2;
#endif
//PGM

    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)
    {
//PGM
#ifdef ROGUE_GRAVITY
        test[0] = trace.endpos[0];
        test[1] = trace.endpos[1];
        if(ent->gravityVector[2] > 0)
            test[2] = trace.endpos[2] + ent->maxs[2] - 1;
        else
            test[2] = trace.endpos[2] + ent->mins[2] + 1;
#else
        test[0] = trace.endpos[0];
        test[1] = trace.endpos[1];
        test[2] = trace.endpos[2] + ent->mins[2] + 1;
#endif
//PGM

        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);

//PGM
    new_bad = CheckForBadArea(ent);
    if(!current_bad && new_bad)
    {
        if (new_bad->owner)
        {
            if ((g_showlogic) && (g_showlogic->value))
                gi.dprintf("Blocked -");
            if (!strcmp(new_bad->owner->classname, "tesla"))
            {
                if ((g_showlogic) && (g_showlogic->value))
                    gi.dprintf ("it's a tesla -");
                if ((!(ent->enemy)) || (!(ent->enemy->inuse)))
                {
                    if ((g_showlogic) && (g_showlogic->value))
                        gi.dprintf ("I don't have a valid enemy!\n");
                }
                else if (!strcmp(ent->enemy->classname, "telsa"))
                {
                    if ((g_showlogic) && (g_showlogic->value))
                        gi.dprintf ("but we're already mad at a tesla\n");
                }
                else if ((ent->enemy) && (ent->enemy->client))
                {
                    if ((g_showlogic) && (g_showlogic->value))
                        gi.dprintf ("we have a player enemy -");
                    if (visible(ent, ent->enemy))
                    {
                        if ((g_showlogic) && (g_showlogic->value))
                            gi.dprintf ("we can see him -");
                    }
                    else
                    {
                        if ((g_showlogic) && (g_showlogic->value))
                            gi.dprintf ("can't see him, kill the tesla! -");
                    }
                }
                else
                {
                    if ((g_showlogic) && (g_showlogic->value))
                        gi.dprintf ("the enemy isn't a player -");
                }
            }
        }
        gi.dprintf ("\n");


        VectorCopy (oldorg, ent->s.origin);
        return false;
    }
//PGM

    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;
}
Пример #10
0
//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;//, tr;
	int			i;
	float		stepsize;
	vec3_t		test;
	int			contents;
	int			jump=0;

// 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)) || (ent->waterlevel > 1))
	{
	//	gi.dprintf("trying to swim\n");
	// 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;
			}
			//gi.dprintf("swim move failed\n");
			
			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;
 
	// this trace checks from a position one step above the entity (at top of bbox)
	// to one step below the entity (bottom of bbox)
	trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);

	// there is an obstruction bigger than a step
	if (trace.allsolid)
//GHz START
	{
		// az: Regular monsters: don't jump on invasion mode...
		if (!G_GetClient(ent) && invasion->value) 
			return false;

		// try to jump over it
		if (G_EntIsAlive(trace.ent) || !CanJumpUp(ent, neworg, end))
			return false;
		else
		{
			jump = 1;
		}
	}
//GHz END

	// not enough room at this height--head of bbox intersects something solid
	// so push down and just try to walk forward at floor height
	else 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 & (CONTENTS_LAVA|CONTENTS_SLIME))
			return false;
	}

//GHz 5/8/2010 - don't get stuck on steep little ramps
	if (trace.fraction < 1 && trace.plane.normal[2] < 0.7) // too steep
		return false;

//GHz START
//	if (CanJumpDown(ent, trace.endpos))
//		jump = -1;
//GHz END

//	VectorSubtract(trace.endpos, oldorg, forward);
//	VectorNormalize(forward);
//	VectorMA(oldorg, 32, forward, end);

//	VectorAdd(trace.endpos, move, end);
//	VectorAdd(end, move, end);

	if ((trace.fraction == 1) && (jump != 1))
	{
		//gi.dprintf("going to fall\n");
	// if monster had the ground pulled out, go ahead and fall
	//	VectorSubtract(trace.endpos, oldorg, forward);
	//	VectorMA(oldorg, 64, forward, end);
		if (!CanJumpDown(ent, trace.endpos))
		{
			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
		}
		else
			jump = -1;
	}

// check point traces down for dangling corners
	//GHz START
	/*
	// fix for monsters walking thru walls
	tr = gi.trace(trace.endpos, ent->mins, ent->maxs, trace.endpos, ent, MASK_SOLID);
	if (tr.contents & MASK_SOLID)
		return false;
	*/
	//GHz END
	
	if (jump != 1)
		VectorCopy (trace.endpos, ent->s.origin);
	
	if (!M_CheckBottom (ent))
	{
		//gi.dprintf("partial ground\n");
		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;
		}
		if (CanJumpDown(ent, trace.endpos))
			jump = -1;
		if (!jump)
		{
			VectorCopy (oldorg, ent->s.origin);
			return false;
		}
	}
	else if (jump == -1)
		jump = 0;
/*
	if (jump)
	{
		VectorCopy(oldorg, ent->s.origin);
		CanJumpDown(ent, trace.endpos, true);
		VectorCopy(trace.endpos, ent->s.origin);
	}
*/
	
	if ( ent->flags & FL_PARTIALGROUND )
	{
		ent->flags &= ~FL_PARTIALGROUND;
	}

	ent->groundentity = trace.ent;
	if (trace.ent)
		ent->groundentity_linkcount = trace.ent->linkcount;

	if (jump == -1)
	{
		/*
		gi.WriteByte (svc_temp_entity);
		gi.WriteByte (TE_DEBUGTRAIL);
		gi.WritePosition (oldorg);
		gi.WritePosition (end);
		gi.multicast (end, MULTICAST_ALL);
		*/

		//VectorScale(move, 10, ent->velocity);
		//ent->velocity[2] = 200;
	}
	else if (jump == 1)
	{
		ent->velocity[2] = 200;
		//gi.dprintf("jumped at %d\n",level.framenum);
	}

// the move is ok
	if (relink)
	{
		gi.linkentity (ent);
		G_TouchTriggers (ent);
	}
	//gi.dprintf("moved successfully at %d\n", level.framenum);
	return true;
}
Пример #11
0
// modified SV_movestep for use with player-controlled monsters
qboolean M_Move (edict_t *ent, vec3_t move, qboolean relink)
{
	vec3_t		oldorg, neworg, end;
	trace_t		trace;//, tr;
	float		stepsize=STEPSIZE;

// try the move	
	VectorCopy (ent->s.origin, oldorg);
	VectorAdd (ent->s.origin, move, neworg);

	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)
	{
		// if we would have collided with a live entity, call its touch function
		// this prevents player-monsters from being invulnerable to obstacles
		if (G_EntIsAlive(trace.ent) && trace.ent->touch)
			trace.ent->touch(trace.ent, ent, &trace.plane, trace.surface);
		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;
	}

	if (trace.fraction == 1)
	{
	//	gi.dprintf("going to fall\n");
	// if monster had the ground pulled out, go ahead and fall
	//	VectorSubtract(trace.endpos, oldorg, forward);
	//	VectorMA(oldorg, 64, forward, end);
	
		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;
		}
	}

// 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;
		}
	}
	
	if (ent->flags & FL_PARTIALGROUND)
		ent->flags &= ~FL_PARTIALGROUND;

	ent->groundentity = trace.ent;
	if (trace.ent)
		ent->groundentity_linkcount = trace.ent->linkcount;

// the move is ok
	if (relink)
	{
		gi.linkentity (ent);
		G_TouchTriggers (ent);
	}

	return true;
}
Пример #12
0
//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;
	float		jumpheight;
	vec3_t		test;
	int			contents;

	qboolean	canjump;
	float		d1, d2;
	int			jump;		// 1=jump up, -1=jump down
	vec3_t		forward, up;
	vec3_t		dir;
	vec_t		dist;
	vec_t		g1, g2;
	edict_t		*grenade;
	edict_t		*target;

	// try the move	
	VectorCopy (ent->s.origin, oldorg);
	VectorAdd (ent->s.origin, move, neworg);

	AngleVectors(ent->s.angles,forward,NULL,up);
	if(ent->enemy)
		target = ent->enemy;
	else if(ent->movetarget)
		target = ent->movetarget;
	else
		target = NULL;

	// 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);

	// Determine whether monster is capable of and/or should jump
	jump = 0;
	if((ent->monsterinfo.jump) && !(ent->monsterinfo.aiflags & AI_DUCKED))
	{
		// Don't jump if path is blocked by monster or player. Otherwise,
		// monster might attempt to jump OVER the monster/player, which 
		// ends up looking a bit goofy. Also don't jump if the monster's
		// movement isn't deliberate (target=NULL)
		if(trace.ent && (trace.ent->client || (trace.ent->svflags & SVF_MONSTER)))
			canjump = false;
		else if(target)
		{
			// Never jump unless it places monster closer to his goal
			vec3_t	dir;
			VectorSubtract(target->s.origin, oldorg, dir);
			d1 = VectorLength(dir);
			VectorSubtract(target->s.origin, trace.endpos, dir);
			d2 = VectorLength(dir);
			if(d2 < d1)
				canjump = true;
			else
				canjump = false;
		}
		else
			canjump = false;
	}
	else
		canjump = false;

	if (trace.allsolid)
	{
		if(canjump && (ent->monsterinfo.jumpup > 0))
		{
			neworg[2] += ent->monsterinfo.jumpup - stepsize;
			trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
			if (!trace.allsolid && !trace.startsolid && trace.fraction > 0 && (trace.plane.normal[2] > 0.9))
			{
				if(!trace.ent || (!trace.ent->client && !(trace.ent->svflags & SVF_MONSTER) && !(trace.ent->svflags & SVF_DEADMONSTER)))
				{
					// Good plane to jump on. Make sure monster is more or less facing
					// the obstacle to avoid cutting-corners jumps
					trace_t	tr;
					vec3_t	p2;

					VectorMA(ent->s.origin,1024,forward,p2);
					tr = gi.trace(ent->s.origin,ent->mins,ent->maxs,p2,ent,MASK_MONSTERSOLID);
					if(DotProduct(tr.plane.normal,forward) < -0.95)
					{
						jump = 1;
						jumpheight = trace.endpos[2] - ent->s.origin[2];
					}
					else
						return false;
				}
			}
			else
				return false;
		}
		else
			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
	// Lazarus: misc_actors don't go swimming, but wading is fine
	if (ent->monsterinfo.aiflags & AI_ACTOR)
	{
		// First check for lava/slime under feet - but only if we're not already in
		// a liquid
		test[0] = trace.endpos[0];
		test[1] = trace.endpos[1];
		if (ent->waterlevel == 0)
		{
			test[2] = trace.endpos[2] + ent->mins[2] + 1;	
			contents = gi.pointcontents(test);
			if (contents & (CONTENTS_LAVA | CONTENTS_SLIME))
				return false;
		}
		test[2] = trace.endpos[2] + ent->viewheight - 1;
		contents = gi.pointcontents(test);
		if (contents & MASK_WATER)
			return false;
	}
	else 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;
	}

	// Lazarus: Don't intentionally move closer to a grenade,
	//          but don't perform this check if we're already evading some
	//          other problem (maybe even this grenade)
	if(!(ent->monsterinfo.aiflags & AI_CHASE_THING))
	{
		grenade = NULL;
		while( (grenade=findradius(grenade,neworg,128)) != NULL)
		{
			if(!grenade->inuse)
				continue;
			if(!grenade->classname)
				continue;
			if(!Q_stricmp(grenade->classname,"grenade") || !Q_stricmp(grenade->classname,"hgrenade"))
			{
				VectorSubtract(grenade->s.origin,oldorg,dir);
				g1 = VectorLength(dir);
				VectorSubtract(grenade->s.origin,neworg,dir);
				g2 = VectorLength(dir);
				if(g2 < g1)
					return false;
			}
		}
	}
	// Lazarus: Don't intentionally walk into lasers.
	dist = VectorLength(move);
	if(dist > 0.)
	{
		edict_t		*e;
		trace_t		laser_trace;
		vec_t		delta;
		vec3_t		laser_mins, laser_maxs;
		vec3_t		laser_start, laser_end;
		vec3_t		monster_mins, monster_maxs;

		for(i=game.maxclients+1; i<globals.num_edicts; i++)
		{
			e = &g_edicts[i];
			if(!e->inuse)
				continue;
			if(!e->classname)
				continue;
			if(Q_stricmp(e->classname,"target_laser"))
				continue;
			if(e->svflags & SVF_NOCLIENT)
				continue;
			if( (e->style == 2) || (e->style == 3))
				continue;
			if(!gi.inPVS(ent->s.origin,e->s.origin))
				continue;
			// Check to see if monster is ALREADY in the path of this laser.
			// If so, allow the move so he can get out.
			VectorMA(e->s.origin,2048,e->movedir,laser_end);
			laser_trace = gi.trace(e->s.origin,NULL,NULL,laser_end,NULL,CONTENTS_SOLID|CONTENTS_MONSTER);
			if(laser_trace.ent == ent)
				continue;
			VectorCopy(laser_trace.endpos,laser_end);
			laser_mins[0] = min(e->s.origin[0],laser_end[0]);
			laser_mins[1] = min(e->s.origin[1],laser_end[1]);
			laser_mins[2] = min(e->s.origin[2],laser_end[2]);
			laser_maxs[0] = max(e->s.origin[0],laser_end[0]);
			laser_maxs[1] = max(e->s.origin[1],laser_end[1]);
			laser_maxs[2] = max(e->s.origin[2],laser_end[2]);
			monster_mins[0] = min(oldorg[0],trace.endpos[0]) + ent->mins[0];
			monster_mins[1] = min(oldorg[1],trace.endpos[1]) + ent->mins[1];
			monster_mins[2] = min(oldorg[2],trace.endpos[2]) + ent->mins[2];
			monster_maxs[0] = max(oldorg[0],trace.endpos[0]) + ent->maxs[0];
			monster_maxs[1] = max(oldorg[1],trace.endpos[1]) + ent->maxs[1];
			monster_maxs[2] = max(oldorg[2],trace.endpos[2]) + ent->maxs[2];
			if( monster_maxs[0] < laser_mins[0] ) continue;
			if( monster_maxs[1] < laser_mins[1] ) continue;
			if( monster_maxs[2] < laser_mins[2] ) continue;
			if( monster_mins[0] > laser_maxs[0] ) continue;
			if( monster_mins[1] > laser_maxs[1] ) continue;
			if( monster_mins[2] > laser_maxs[2] ) continue;
			// If we arrive here, some part of the bounding box surrounding
			// monster's total movement intersects laser bounding box.
			// If laser is parallel to x, y, or z, we definitely
			// know this move will put monster in path of laser
			if ( (e->movedir[0] == 1.) || (e->movedir[1] == 1.) || (e->movedir[2] == 1.))
				return false;
			// Shift psuedo laser towards monster's current position up to
			// the total distance he's proposing moving.
			delta = min(16,dist);
			VectorNormalize2(move,dir);
			while(delta < dist+15.875)
			{
				if(delta > dist) delta = dist;
				VectorMA(e->s.origin,    -delta,dir,laser_start);
				VectorMA(e->s.old_origin,-delta,dir,laser_end);
				laser_trace = gi.trace(laser_start,NULL,NULL,laser_end,world,CONTENTS_SOLID|CONTENTS_MONSTER);
				if(laser_trace.ent == ent)
					return false;
				delta += 16;
			}
		}
	}
	if ((trace.fraction == 1) && !jump && canjump && (ent->monsterinfo.jumpdn > 0))
	{
		end[2] = oldorg[2] + move[2] - ent->monsterinfo.jumpdn;
		trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID | MASK_WATER);
		if(trace.fraction < 1 && (trace.plane.normal[2] > 0.9) && (trace.contents & MASK_SOLID) && (neworg[2] - 16 > trace.endpos[2]))
		{
			if(!trace.ent || (!trace.ent->client && !(trace.ent->svflags & SVF_MONSTER) && !(trace.ent->svflags & SVF_DEADMONSTER)))
				jump = -1;
		}
	}


	if ((trace.fraction == 1) && !jump)
	{
		// 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(!jump)
	{
		qboolean	skip = false;
		// if monster CAN jump down, and a position just a bit forward would be 
		// a good jump-down spot, allow (briefly) !M_CheckBottom
		if (canjump && target && (target->s.origin[2] < ent->s.origin[2]) && (ent->monsterinfo.jumpdn > 0))
		{
			vec3_t		p1, p2;
			trace_t		tr;

			VectorMA(oldorg,48,forward,p1);
			tr = gi.trace(ent->s.origin, ent->mins, ent->maxs, p1, ent, MASK_MONSTERSOLID);
			if(tr.fraction == 1)
			{
				p2[0] = p1[0];
				p2[1] = p1[1];
				p2[2] = p1[2] - ent->monsterinfo.jumpdn;
				tr = gi.trace(p1,ent->mins,ent->maxs,p2,ent,MASK_MONSTERSOLID | MASK_WATER);
				if(tr.fraction < 1 && (tr.plane.normal[2] > 0.9) && (tr.contents & MASK_SOLID) && (p1[2] - 16 > tr.endpos[2]))
				{
					if(!tr.ent || (!tr.ent->client && !(tr.ent->svflags & SVF_MONSTER) && !(tr.ent->svflags & SVF_DEADMONSTER)))
					{
						VectorSubtract(target->s.origin, tr.endpos, dir);
						d2 = VectorLength(dir);
						if(d2 < d1)
							skip = true;
					}
				}
			}

		}
		if (!skip)
		{
			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;
	if(trace.ent)
		ent->groundentity_linkcount = trace.ent->linkcount;

// the move is ok
	if(jump)
	{
		VectorScale(move, 10, ent->velocity);
		if(jump > 0)
		{
			ent->monsterinfo.jump(ent);
			ent->velocity[2] = 2.5*jumpheight + 80;
		}
		else
		{
			ent->velocity[2] = max(ent->velocity[2],100);
			if(oldorg[2] - ent->s.origin[2] > 48)
				ent->s.origin[2] = oldorg[2] + ent->velocity[2]*FRAMETIME;
		}
		if(relink)
		{
			gi.linkentity (ent);
			G_TouchTriggers (ent);
		}
	}
	else if (relink)
	{
		gi.linkentity (ent);
		G_TouchTriggers (ent);
	}
	return true;
}
Пример #13
0
//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;
    edict_t		*current_bad = NULL;		// PGM
    float		minheight;			// pmm

    //======
    //PGM

    // PMM - who cares about bad areas if you're dead?
    if (ent->health > 0)
    {
        current_bad = CheckForBadArea(ent);
        if(current_bad)
        {
            ent->bad_area = current_bad;

            if(ent->enemy && !strcmp(ent->enemy->classname, "tesla"))
            {
                // if the tesla is in front of us, back up...
                if (IsBadAhead (ent, current_bad, move))
                    VectorScale(move, -1, move);
            }
        }
        else if(ent->bad_area)
        {
            // if we're no longer in a bad area, get back to business.
            ent->bad_area = NULL;
            if(ent->oldenemy)// && ent->bad_area->owner == ent->enemy)
            {
                ent->enemy = ent->oldenemy;
                ent->goalentity = ent->oldenemy;
                FoundTarget(ent);
                return true;
            }
        }
    }
    //PGM
    //======

    // 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)
                {
                    // we want the carrier to stay a certain distance off the ground, to help prevent him
                    // from shooting his fliers, who spawn in below him
                    //
                    if (!strcmp(ent->classname, "monster_carrier"))
                        minheight = 104;
                    else
                        minheight = 40;
                    if (dz > minheight)
                        //	pmm
                        neworg[2] -= 8;
                    if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))
                        if (dz < (minheight - 10))
                            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;
                }
            }

            // PMM - changed above to this
            if ((trace.fraction == 1) && (!trace.allsolid) && (!trace.startsolid))
            {
                VectorCopy (trace.endpos, ent->s.origin);
                //=====
                //PGM
                if(!current_bad && CheckForBadArea(ent))
                {
                    VectorCopy (oldorg, ent->s.origin);
                }
                else
                {
                    if (relink)
                    {
                        gi.linkentity (ent);
                        G_TouchTriggers (ent);
                    }
                    return true;
                }
                //PGM
                //=====
            }

            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;

    //PGM
    // trace from 1 stepsize gravityUp to 2 stepsize gravityDown.
    VectorMA(neworg, -1 * stepsize, ent->gravityVector, neworg);
    VectorMA(neworg, 2 * stepsize, ent->gravityVector, end);
    //PGM

    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)
    {
        //PGM
        test[0] = trace.endpos[0];
        test[1] = trace.endpos[1];
        if(ent->gravityVector[2] > 0)
            test[2] = trace.endpos[2] + ent->maxs[2] - 1;
        else
            test[2] = trace.endpos[2] + ent->mins[2] + 1;
        //PGM

        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);

    //PGM
    // PMM - don't bother with bad areas if we're dead
    if (ent->health > 0)
    {
        // use AI_BLOCKED to tell the calling layer that we're now mad at a tesla
        new_bad = CheckForBadArea(ent);
        if(!current_bad && new_bad)
        {
            if (new_bad->owner)
            {
                if (!strcmp(new_bad->owner->classname, "tesla"))
                {
                    if ((!(ent->enemy)) || (!(ent->enemy->inuse)))
                    {
                        TargetTesla (ent, new_bad->owner);
                        ent->monsterinfo.aiflags |= AI_BLOCKED;
                    }
                    else if (!strcmp(ent->enemy->classname, "telsa"))
                    {
                    }
                    else if ((ent->enemy) && (ent->enemy->client))
                    {
                        if (visible(ent, ent->enemy))
                        {
                        }
                        else
                        {
                            TargetTesla (ent, new_bad->owner);
                            ent->monsterinfo.aiflags |= AI_BLOCKED;
                        }
                    }
                    else
                    {
                        TargetTesla (ent, new_bad->owner);
                        ent->monsterinfo.aiflags |= AI_BLOCKED;
                    }
                }
            }

            VectorCopy (oldorg, ent->s.origin);
            return false;
        }
    }
    //PGM

    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;

    if (relink)
    {
        gi.linkentity (ent);
        G_TouchTriggers (ent);
    }
    return true;
}
Пример #14
0
void SV_Physics_Step (edict_t *ent)
{
	qboolean	wasonground;
	qboolean	hitsound = false;
	float		*vel;
	float		speed, newspeed, control;
	float		friction;
	edict_t		*groundentity;
	int			mask;
//	vec3_t		dir;


	// airborn monsters should always check for ground
//	if (!ent->groundentity)
		M_CheckGround (ent);

	groundentity = ent->groundentity;

	SV_CheckVelocity (ent);

	if (groundentity)
		wasonground = true;
	else
		wasonground = false;
		
//	if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
//		SV_AddRotationalFriction (ent);

	// add gravity except:
	//   flying monsters
	//   swimming monsters who are in the water
	if (! wasonground)
		if (!(ent->flags & FL_FLY))
			if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
			{
				if (ent->velocity[2] < sv_gravity->value*-0.1)
					hitsound = true;
				if (ent->waterlevel == 0)
					SV_AddGravity (ent);
			}

	// friction for flying monsters that have been given vertical velocity
	if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
	{
//gi.bprintf(PRINT_HIGH,"FLY!\n");
		speed = fabs(ent->velocity[2]);
		control = speed < sv_stopspeed ? sv_stopspeed : speed;
		friction = sv_friction/3;
		newspeed = speed - (FRAMETIME * control * friction);
		if (newspeed < 0)
			newspeed = 0;
		newspeed /= speed;
		ent->velocity[2] *= newspeed;
	}

	// friction for flying monsters that have been given vertical velocity
	if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
	{
//gi.bprintf(PRINT_HIGH,"SWIM!\n");
		//K03 Begin
		float water_friction;
		//K03 End
		speed = fabs(ent->velocity[2]);
		control = speed < sv_stopspeed ? sv_stopspeed : speed;
		//K03 Begin
		water_friction=(FRAMETIME * control * sv_waterfriction * ent->waterlevel);
		//newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
		if ((ent->myskills.abilities[SUPER_SPEED].current_level < 1) || (ent->myskills.abilities[SUPER_SPEED].disable))
			newspeed = speed;
		else
			newspeed = speed - water_friction;
		//K03 End
		if (newspeed < 0)
			newspeed = 0;
		newspeed /= speed;
		ent->velocity[2] *= newspeed;
	}

	if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
	{
		// apply friction
		// let dead monsters who aren't completely onground slide
		if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
			if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
			{
				//K03 Begin
				float water_friction;
				//K03 End
				vel = ent->velocity;
				speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
				if (speed)
				{
					friction = sv_friction;

					control = speed < sv_stopspeed ? sv_stopspeed : speed;
					newspeed = speed - FRAMETIME*control*friction;
					//K03 Begin
					water_friction=FRAMETIME*control*friction;
					//newspeed = speed - FRAMETIME*control*friction;
					if ( ((ent->myskills.abilities[SUPER_SPEED].current_level < 1) || (ent->myskills.abilities[SUPER_SPEED].disable))
						&& !(ent->flags & FL_SWIM))
						newspeed = speed;
					else
						newspeed = speed - water_friction;
					//K03 End

					if (newspeed < 0)
						newspeed = 0;
					newspeed /= speed;

					vel[0] *= newspeed;
					vel[1] *= newspeed;
				}
			}

		if (ent->svflags & SVF_MONSTER)
		{
			if(!deathmatch->value) mask = MASK_MONSTERSOLID;
			else mask = MASK_BOTSOLIDX;//MASK_PLAYERSOLID;
		}
		else
			mask = MASK_SOLID;
		//FIXME: warning - SV_FlyMove() can cause an entity to be freed
		SV_FlyMove (ent, FRAMETIME, mask);

		gi.linkentity (ent);
//		G_TouchTriggers (ent);
	}
	else
		V_TouchSolids(ent);

// regular thinking
	SV_RunThink (ent); 
}
Пример #15
0
void SV_Physics_Step (edict_t *ent)
{
	qboolean wasonground;
	qboolean hitsound = false;
	float *vel;
	float speed, newspeed, control;
	float friction;
	edict_t *groundentity;
	int mask;

	if (!ent)
	{
		return;
	}

	/* airborn monsters should always check for ground */
	if (!ent->groundentity)
	{
		M_CheckGround(ent);
	}

	groundentity = ent->groundentity;

	SV_CheckVelocity(ent);

	if (groundentity)
	{
		wasonground = true;
	}
	else
	{
		wasonground = false;
	}

	if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
	{
		SV_AddRotationalFriction(ent);
	}

	/* add gravity except:
	    - flying monsters
	    - swimming monsters who are in the water */
	if (!wasonground)
	{
		if (!(ent->flags & FL_FLY))
		{
			if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
			{
				if (ent->velocity[2] < sv_gravity->value * -0.1)
				{
					hitsound = true;
				}

				if (ent->waterlevel == 0)
				{
					SV_AddGravity(ent);
				}
			}
		}
	}

	/* friction for flying monsters that have been given vertical velocity */
	if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
	{
		speed = fabs(ent->velocity[2]);
		control = speed < sv_stopspeed ? sv_stopspeed : speed;
		friction = sv_friction / 3;
		newspeed = speed - (FRAMETIME * control * friction);

		if (newspeed < 0)
		{
			newspeed = 0;
		}

		newspeed /= speed;
		ent->velocity[2] *= newspeed;
	}

	/* friction for flying monsters that have been given vertical velocity */
	if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
	{
		speed = fabs(ent->velocity[2]);
		control = speed < sv_stopspeed ? sv_stopspeed : speed;
		newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);

		if (newspeed < 0)
		{
			newspeed = 0;
		}

		newspeed /= speed;
		ent->velocity[2] *= newspeed;
	}

	if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
	{
		/* let dead monsters who aren't completely onground slide */
		if ((wasonground) || (ent->flags & (FL_SWIM | FL_FLY)))
		{
			if (!((ent->health <= 0.0) && !M_CheckBottom(ent)))
			{
				vel = ent->velocity;
				speed = sqrt(vel[0] * vel[0] + vel[1] * vel[1]);

				if (speed)
				{
					friction = sv_friction;

					control = speed < sv_stopspeed ? sv_stopspeed : speed;
					newspeed = speed - FRAMETIME * control * friction;

					if (newspeed < 0)
					{
						newspeed = 0;
					}

					newspeed /= speed;

					vel[0] *= newspeed;
					vel[1] *= newspeed;
				}
			}
		}

		if (ent->svflags & SVF_MONSTER)
		{
			mask = MASK_MONSTERSOLID;
		}
		else
		{
			mask = MASK_SOLID;
		}

		SV_FlyMove(ent, FRAMETIME, mask);

		gi.linkentity(ent);
		G_TouchTriggers(ent);

		if (!ent->inuse)
		{
			return;
		}

		if (ent->groundentity)
		{
			if (!wasonground)
			{
				if (hitsound)
				{
					gi.sound(ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
				}
			}
		}
	}

	/* regular thinking */
	SV_RunThink(ent);
}
Пример #16
0
///////////////////////////////////////////////////////////////////////
// Wandering code (based on old ACE movement code) 
///////////////////////////////////////////////////////////////////////
void ACEMV_Wander(edict_t *self, usercmd_t *ucmd)
{
	vec3_t  temp;
	
	// Do not move
	if(self->next_move_time > level.time)
		return;

	// Special check for elevators, stand still until the ride comes to a complete stop.
	if(self->groundentity != NULL && self->groundentity->use == Use_Plat)
		if(self->groundentity->moveinfo.state == STATE_UP ||
		   self->groundentity->moveinfo.state == STATE_DOWN) // only move when platform not
		{
			self->velocity[0] = 0;
			self->velocity[1] = 0;
			self->velocity[2] = 0;
			self->next_move_time = level.time + 0.5;
			return;
		}
	
	// Is there a target to move to
	if (self->movetarget)
		ACEMV_MoveToGoal(self,ucmd);
		
	////////////////////////////////
	// Swimming?
	////////////////////////////////
	VectorCopy(self->s.origin,temp);
	temp[2]+=24;

	if(gi.pointcontents (temp) & MASK_WATER)
	{
		// If drowning and no node, move up
		if(self->client->next_drown_time > 0)
		{
			ucmd->upmove = 1;	
			self->s.angles[PITCH] = -45; 
		}
		else
			ucmd->upmove = 15;	

		ucmd->forwardmove = 300;
	}
	else
		self->client->next_drown_time = 0; // probably shound not be messing with this, but
	
	////////////////////////////////
	// Lava?
	////////////////////////////////
	temp[2]-=48;	
	if(gi.pointcontents(temp) & (CONTENTS_LAVA|CONTENTS_SLIME))
	{
		//	safe_bprintf(PRINT_MEDIUM,"lava jump\n");
		self->s.angles[YAW] += random() * 360 - 180; 
		ucmd->forwardmove = 400;
		ucmd->upmove = 400;
		return;
	}

	if(ACEMV_CheckEyes(self,ucmd))
		return;
	
	// Check for special movement if we have a normal move (have to test)
 	if(VectorLength(self->velocity) < 37)
	{
		if(random() > 0.1 && ACEMV_SpecialMove(self,ucmd))
			return;

		self->s.angles[YAW] += random() * 180 - 90; 

		if(!M_CheckBottom(self) || !self->groundentity) // if there is ground continue otherwise wait for next move
			ucmd->forwardmove = 400;
		
		return;
	}
	
	ucmd->forwardmove = 400;

}