Esempio n. 1
0
/*
===============
findEmptySpot

Finds an empty spot radius units from origin
==============
*/
static void findEmptySpot(vec3_t origin, float radius, vec3_t spot)
{
    int i, j, k;
    vec3_t delta, test, total;
    trace_t tr;

    VectorClear(total);

    // 54(!) traces to test for empty spots
    for (i = -1; i <= 1; i++)
    {
        for (j = -1; j <= 1; j++)
        {
            for (k = -1; k <= 1; k++)
            {
                VectorSet(delta, (i * radius), (j * radius), (k * radius));

                VectorAdd(origin, delta, test);

                G_Trace(&tr, test, NULL, NULL, test, -1, MASK_SOLID);

                if (!tr.allsolid)
                {
                    G_Trace(&tr, test, NULL, NULL, origin, -1, MASK_SOLID);
                    VectorScale(delta, tr.fraction, delta);
                    VectorAdd(total, delta, total);
                }
            }
        }
    }

    VectorNormalize(total);
    VectorScale(total, radius, total);
    VectorAdd(origin, total, spot);
}
//
// Name:        CanSeeEntity()
// Parameters:  Entity *start - The entity trying to see
//              Entity *target - The entity that needs to be seen
//              qboolean useFOV - take FOV into consideration or not
//              qboolean useVisionDistance - take visionDistance into consideration
// Description: Wraps a lot of the different CanSee Functions into one
//
qboolean SensoryPerception::CanSeeEntity( Entity *start, const Entity *target, qboolean useFOV, qboolean useVisionDistance )
{
	
	// Check for NULL
	if ( !start || !target )
		return false;
	
	// Check if This Actor can even see at all
	if ( !ShouldRespondToStimuli( StimuliSight ) )
		return false;
	
	// Check for FOV
	if ( useFOV )
	{
		if ( !InFOV( target ) )
			return false;
	}
	
	// Check for vision distance
	if ( useVisionDistance )
	{
		if ( !WithinVisionDistance( target ) )
			return false;
	}
	
	// Do Trace
	auto p = target->centroid;
	auto eyePos = vec_zero;
	
	// If the start entity is an actor, then we want to add in the eyeposition
	if ( start->isSubclassOf ( Actor ) )
	{
		Actor *a;
		a = dynamic_cast<Actor*>(start);
		
		if ( !a )
			return false;
		
		eyePos = a->EyePosition();
		
	}
	
	// Check if he's visible
	auto trace = G_Trace( eyePos, vec_zero, vec_zero, p, target, MASK_OPAQUE, false, "SensoryPerception::CanSeeEntity" );
	
	if ( trace.fraction == 1.0f || trace.ent == target->edict )
		return true;
	
	// Check if his head is visible
	p.z = target->absmax.z;
	trace = G_Trace( eyePos, vec_zero, vec_zero, p, target, MASK_OPAQUE, false, "SensoryPerception::CanSeeEntity" );
	if ( trace.fraction == 1.0f || trace.ent == target->edict )
		return true;			
	
	return false;
	
}
Esempio n. 3
0
/*
* G_ProjectThirdPersonView
*/
static void G_ProjectThirdPersonView( vec3_t vieworg, vec3_t viewangles, edict_t *passent )
{
	float thirdPersonRange = 60;
	float thirdPersonAngle = 0;
	float dist, f, r;
	vec3_t dest, stop;
	vec3_t chase_dest;
	trace_t	trace;
	vec3_t mins = { -4, -4, -4 };
	vec3_t maxs = { 4, 4, 4 };
	vec3_t v_forward, v_right, v_up;

	AngleVectors( viewangles, v_forward, v_right, v_up );

	// calc exact destination
	VectorCopy( vieworg, chase_dest );
	r = DEG2RAD( thirdPersonAngle );
	f = -cos( r );
	r = -sin( r );
	VectorMA( chase_dest, thirdPersonRange * f, v_forward, chase_dest );
	VectorMA( chase_dest, thirdPersonRange * r, v_right, chase_dest );
	chase_dest[2] += 8;

	// find the spot the player is looking at
	VectorMA( vieworg, 512, v_forward, dest );
	G_Trace( &trace, vieworg, mins, maxs, dest, passent, MASK_SOLID );

	// calculate pitch to look at the same spot from camera
	VectorSubtract( trace.endpos, vieworg, stop );
	dist = sqrt( stop[0] * stop[0] + stop[1] * stop[1] );
	if( dist < 1 )
		dist = 1;
	viewangles[PITCH] = RAD2DEG( -atan2( stop[2], dist ) );
	viewangles[YAW] -= thirdPersonAngle;
	AngleVectors( viewangles, v_forward, v_right, v_up );

	// move towards destination
	G_Trace( &trace, vieworg, mins, maxs, chase_dest, passent, MASK_SOLID );

	if( trace.fraction != 1.0 )
	{
		VectorCopy( trace.endpos, stop );
		stop[2] += ( 1.0 - trace.fraction ) * 32;
		G_Trace( &trace, vieworg, mins, maxs, stop, passent, MASK_SOLID );
		VectorCopy( trace.endpos, chase_dest );
	}

	VectorCopy( chase_dest, vieworg );
}
//
// Name:        CanSeeEntity()
// Parameters:  Vector &start -- The starting position
//              Entity *target - The entity that needs to be seen
//              qboolean useFOV - take FOV into consideration or not
//              qboolean useVisionDistance - take visionDistance into consideration
// Description: Wraps a lot of the different CanSee Functions into one
//
qboolean SensoryPerception::CanSeeEntity( const Vector &start , const Entity *target, qboolean useFOV , qboolean useVisionDistance )
{
	// Check for NULL
	if ( !target )
		return false;
	
	// Check if This Actor can even see at all
	if ( !ShouldRespondToStimuli( StimuliSight ) )
		return false;
	
	
	// Check for FOV
	if ( useFOV )
	{
		if ( !InFOV( target ) )
			return false;
	}
	
	// Check for vision distance
	if ( useVisionDistance )
	{
		if ( !WithinVisionDistance( target ) )
			return false;
	}
	
	// Do Trace
	auto realStart = start;	
	auto p = target->centroid;
	
	// Add in the eye offset
	
	auto eyePos = act->EyePosition() - act->origin;
	realStart += eyePos;
	
	// Check if he's visible
	auto trace = G_Trace( realStart, vec_zero, vec_zero, p, act, MASK_OPAQUE, false, "SensoryPerception::CanSeeEntity" );
	if ( trace.fraction == 1.0f || trace.ent == target->edict )
		return true;
	
	// Check if his head is visible
	p.z = target->absmax.z;
	trace = G_Trace( realStart, vec_zero, vec_zero, p, act, MASK_OPAQUE, false, "SensoryPerception::CanSeeEntity" );
	if ( trace.fraction == 1.0f || trace.ent == target->edict )
		return true;			
	
	
	return false;
}
Esempio n. 5
0
/*
* AI_FlagsForNode
* check the world and set up node flags
*/
int AI_FlagsForNode( vec3_t origin, edict_t *passent )
{
	trace_t	trace;
	int flagsmask = 0;
	int contents;

	contents = G_PointContents( origin );
	//water
	if( contents & MASK_WATER )
		flagsmask |= NODEFLAGS_WATER;

	if( contents & CONTENTS_DONOTENTER )
		flagsmask |= NODEFLAGS_DONOTENTER;

	//floor
	G_Trace( &trace, origin, tv( -15, -15, 0 ), tv( 15, 15, 0 ), tv( origin[0], origin[1], origin[2] - AI_JUMPABLE_HEIGHT ), passent, MASK_NODESOLID );
	if( trace.fraction < 1.0 )
		flagsmask &= ~NODEFLAGS_FLOAT; //ok, it wasn't set, I know...
	else
		flagsmask |= NODEFLAGS_FLOAT;

	//ladder
	//	G_Trace( &trace, origin, tv(-18, -18, -16), tv(18, 18, 16), origin, passent, MASK_ALL );
	//	if( trace.startsolid && trace.contents & CONTENTS_LADDER )
	//		flagsmask |= NODEFLAGS_LADDER;

	return flagsmask;
}
Esempio n. 6
0
//==========================================
// AI_CanMove
// Checks if bot can move (really just checking the ground)
// Also, this is not a real accurate check, but does a
// pretty good job and looks for lava/slime.
//==========================================
qboolean AI_CanMove( edict_t *self, int direction )
{
	vec3_t forward, right;
	vec3_t offset, start, end;
	vec3_t angles;
	trace_t tr;

	// Now check to see if move will move us off an edge
	VectorCopy( self->s.angles, angles );

	if( direction == BOT_MOVE_LEFT )
		angles[1] += 90;
	else if( direction == BOT_MOVE_RIGHT )
		angles[1] -= 90;
	else if( direction == BOT_MOVE_BACK )
		angles[1] -= 180;


	// Set up the vectors
	AngleVectors( angles, forward, right, NULL );

	VectorSet( offset, 36, 0, 24 );
	G_ProjectSource( self->s.origin, offset, forward, right, start );

	VectorSet( offset, 36, 0, -100 );
	G_ProjectSource( self->s.origin, offset, forward, right, end );

	G_Trace( &tr, start, NULL, NULL, end, self, MASK_AISOLID );

	if( tr.fraction == 1.0 || tr.contents & ( CONTENTS_LAVA|CONTENTS_SLIME ) )
		return qfalse;

	return qtrue; // yup, can move
}
Esempio n. 7
0
/**
 * @brief Spawns a smoke field that is available for some rounds
 * @param[in] vec The position in the world that is the center of the smoke field
 * @param[in] particle The id of the particle (see ptl_*.ufo script files in base/ufos)
 * @param[in] rounds The number of rounds the particle will last
 * @todo Does '2 rounds' mean: created in player's turn, last through the aliens turn, vanish before the 2nd player's turn ??
 * @param[in] radius The max distance of a cell from the center to get a particle
 */
void G_SpawnSmokeField (const vec3_t vec, const char *particle, int rounds, vec_t radius)
{
	vec_t x, y;

	G_SpawnSmoke(vec, particle, rounds);

	/* for all cells in a square of +/- radius */
	for (x = vec[0] - radius; x <= vec[0] + radius; x += UNIT_SIZE) {
		for (y = vec[1] - radius; y <= vec[1] + radius; y += UNIT_SIZE) {
			vec3_t end;
			trace_t tr;

			VectorSet(end, x, y, vec[2]);

			/* cut off the edges of the square to resemble a circle */
			if (VectorDist(end, vec) > radius)
				continue;
			tr = G_Trace(vec, end, NULL, MASK_SMOKE_AND_FIRE);
			/* trace didn't reach the target - something was hit before */
			if (tr.fraction < 1.0 || (tr.contentFlags & CONTENTS_WATER)) {
				continue;
			}
			G_SpawnSmoke(end, particle, rounds);
		}
	}
}
Esempio n. 8
0
void G_SpawnStunSmokeField (const vec3_t vec, const char *particle, int rounds, int damage, vec_t radius)
{
	vec_t x, y;

	G_SpawnStunSmoke(vec, particle, rounds, damage);

	for (x = vec[0] - radius; x <= vec[0] + radius; x += UNIT_SIZE) {
		for (y = vec[1] - radius; y <= vec[1] + radius; y += UNIT_SIZE) {
			vec3_t end;
			trace_t tr;

			VectorSet(end, x, y, vec[2]);

			if (VectorDist(end, vec) > radius)
				continue;
			tr = G_Trace(vec, end, NULL, MASK_SMOKE_AND_FIRE);
			/* trace didn't reach the target - something was hit before */
			if (tr.fraction < 1.0 || (tr.contentFlags & CONTENTS_WATER)) {
				continue;
			}

			G_SpawnStunSmoke(end, particle, rounds, damage);
		}
	}
}
qboolean SensoryPerception::CanSeePosition( const Vector &start, const Vector &position, qboolean useFOV , qboolean useVisionDistance )
{
	
	// Check if This Actor can even see at all
	if ( !ShouldRespondToStimuli( StimuliSight ) )
		return false;
	
	// Check for FOV
	if ( useFOV )
	{
		if ( !InFOV( position ) )
			return false;
	}
	
	// Check for vision distance
	if ( useVisionDistance )
	{
		if ( !WithinVisionDistance( position ) )
			return false;
	}
	
	// Do Trace
	// Check if he's visible
	auto trace = G_Trace( start, vec_zero, vec_zero, position, act, MASK_OPAQUE, false, "SensoryPerception::CanSeeEntity" );
	if ( trace.fraction == 1.0f )
		return true;
	
	return false;
}
Esempio n. 10
0
bool BotTacticalSpotsCache::FindRunAwayElevatorOrigin( const Vec3 &origin, const Vec3 &enemyOrigin, vec3_t result[2] ) {
	ReachableEntities reachableEntities;
	FindReachableClassEntities( origin, 128.0f + 384.0f * Skill(), "func_plat", reachableEntities );

	trace_t trace;
	const auto *pvsCache = EntitiesPvsCache::Instance();
	edict_t *enemyEnt = const_cast<edict_t *>( self->ai->botRef->selectedEnemies.Ent() );
	edict_t *gameEdicts = game.edicts;
	for( const auto &entAndScore: reachableEntities ) {
		edict_t *ent = gameEdicts + entAndScore.entNum;
		// Can't run away via elevator if the elevator has been always activated
		if( ent->moveinfo.state != STATE_BOTTOM ) {
			continue;
		}

		if( !pvsCache->AreInPvs( enemyEnt, ent ) ) {
			continue;
		}

		G_Trace( &trace, enemyEnt->s.origin, nullptr, nullptr, ent->moveinfo.end_origin, enemyEnt, MASK_AISOLID );
		if( trace.fraction == 1.0f || trace.ent > 0 ) {
			continue;
		}

		// Copy trigger origin
		VectorCopy( ent->s.origin, result[0] );
		// Drop origin to the elevator bottom
		result[0][2] = ent->r.absmin[2] + 16;
		// Copy trigger destination
		VectorCopy( ent->moveinfo.end_origin, result[1] );
		return true;
	}

	return false;
}
Esempio n. 11
0
//==========================================
// BOT_DMclass_CheckShot
// Checks if shot is blocked (doesn't verify it would hit)
//==========================================
static bool BOT_DMclass_CheckShot( edict_t *ent, vec3_t point )
{
	trace_t tr;
	vec3_t start, forward, right, offset;

	if( random() > ent->ai->pers.cha.firerate )
		return false;

	AngleVectors( ent->r.client->ps.viewangles, forward, right, NULL );

	VectorSet( offset, 0, 0, ent->viewheight );
	G_ProjectSource( ent->s.origin, offset, forward, right, start );

	// blocked, don't shoot
	G_Trace( &tr, start, vec3_origin, vec3_origin, point, ent, MASK_AISOLID );
	if( tr.fraction < 0.8f )
	{
		if( tr.ent < 1 || !game.edicts[tr.ent].takedamage || game.edicts[tr.ent].movetype == MOVETYPE_PUSH )
			return false;

		// check if the player we found is at our team
		if( game.edicts[tr.ent].s.team == ent->s.team && GS_TeamBasedGametype() )
			return false;
	}

	return true;
}
Esempio n. 12
0
void Gib::SprayBlood
	(
	Vector start
	)

   {
   Vector      norm;
	trace_t		trace;
	Vector		trace_end;

	trace_end = velocity;
	trace_end.normalize();
	trace_end *= 1000;
	trace_end += start;

   trace = G_Trace( start, vec_zero, vec_zero, trace_end, this, MASK_SOLID, false, "Gib::SprayBlood" );

	if ( HitSky( &level.impact_trace ) || ( !level.impact_trace.ent ) || ( level.impact_trace.ent->solid != SOLID_BSP ) )
		{
		return;
		}

	// Do a bloodsplat
   if ( blood_splat_name.length() )
		{
		Decal *decal = new Decal;
		decal->setShader( blood_splat_name );
		decal->setOrigin( Vector( trace.endpos ) + ( Vector( level.impact_trace.plane.normal ) * 0.2f ) );
		decal->setDirection( level.impact_trace.plane.normal );
		decal->setOrientation( "random" );
		decal->setRadius( blood_splat_size + G_Random( blood_splat_size ) );
		}
   }
Esempio n. 13
0
bool BotTacticalSpotsCache::FindRunAwayJumppadOrigin( const Vec3 &origin, const Vec3 &enemyOrigin, vec3_t result[2] ) {
	ReachableEntities reachableEntities;
	FindReachableClassEntities( origin, 128.0f + 384.0f * Skill(), "trigger_push", reachableEntities );

	trace_t trace;
	const auto *pvsCache = EntitiesPvsCache::Instance();
	edict_t *enemyEnt = const_cast<edict_t *>( self->ai->botRef->selectedEnemies.Ent() );
	for( const auto &entAndScore: reachableEntities ) {
		edict_t *ent = game.edicts + entAndScore.entNum;
		if( !pvsCache->AreInPvs( enemyEnt, ent ) ) {
			continue;
		}

		G_Trace( &trace, enemyEnt->s.origin, nullptr, nullptr, ent->target_ent->s.origin, enemyEnt, MASK_AISOLID );
		if( trace.fraction == 1.0f || trace.ent > 0 ) {
			continue;
		}

		// Copy trigger origin
		VectorCopy( ent->s.origin, result[0] );
		// Copy trigger destination
		VectorCopy( ent->target_ent->s.origin, result[1] );
		return true;
	}

	return false;
}
Esempio n. 14
0
static bool BOT_DMclass_FindRocket( edict_t *self, vec3_t away_from_rocket )
{
#define AI_ROCKET_DETECT_RADIUS 1000
#define AI_ROCKET_DANGER_RADIUS 200
	int i, numtargets;
	int targets[MAX_EDICTS];
	edict_t *target;
	float min_roxx_time = 1.0f;
	bool any_rocket = false;

	numtargets = GClip_FindRadius( self->s.origin, AI_ROCKET_DETECT_RADIUS, targets, MAX_EDICTS );
	for( i = 0; i < numtargets; i++ )
	{
		target = game.edicts + targets[i];

		// Missile detection code
		if( target->r.svflags & SVF_PROJECTILE && target->s.type != ET_PLASMA ) // (plasmas come in bunchs so are too complex for the bot to dodge)
		{
			if( target->r.owner && target->r.owner != self )
			{
				vec3_t end;
				trace_t trace;

				VectorMA( target->s.origin, 2, target->velocity, end );
				G_Trace( &trace, target->s.origin, target->r.mins, target->r.maxs, end, target, MASK_SOLID );
				if( trace.fraction < min_roxx_time )
				{
					vec_t l;

					any_rocket = true;
					min_roxx_time = trace.fraction;
					VectorSubtract( trace.endpos, self->s.origin, end );
					// ok... end is where the impact will be.
					// trace.fraction is the time.

					if( ( l = VectorLengthFast( end ) ) < AI_ROCKET_DANGER_RADIUS )
					{
						RotatePointAroundVector( away_from_rocket, &axis_identity[AXIS_UP], end, -self->s.angles[YAW] );
						VectorNormalize( away_from_rocket );

						if( fabs( away_from_rocket[0] ) < 0.3 ) away_from_rocket[0] = 0;
						if( fabs( away_from_rocket[1] ) < 0.3 ) away_from_rocket[1] = 0;
						away_from_rocket[2] = 0;
						away_from_rocket[0] *= -1.0f;
						away_from_rocket[1] *= -1.0f;

						if( nav.debugMode && bot_showcombat->integer > 2 )
							G_PrintChasersf( self, "%s: ^1projectile dodge: ^2%f, %f d=%f^7\n", self->ai->pers.netname, away_from_rocket[0], away_from_rocket[1], l );
					}
				}
			}
		}
	}

	return any_rocket;

#undef AI_ROCKET_DETECT_RADIUS
#undef AI_ROCKET_DANGER_RADIUS
}
Esempio n. 15
0
bool AI_ReachabilityVisible( edict_t *self, vec3_t point )
{
	trace_t trace;

	G_Trace( &trace, self->s.origin, vec3_origin, vec3_origin, point, self, MASK_DEADSOLID );
	if( trace.ent < 0 )
		return true;

	return false;
}
Esempio n. 16
0
/*
* AI_AddNode_Platform_FindLowerLinkableCandidate
* helper to AI_AddNode_Platform
*/
static int AI_AddNode_Platform_FindLowerLinkableCandidate( edict_t *ent )
{
	trace_t	trace;
	float plat_dist;
	float platlip;
	int numtries = 0, maxtries = 10;
	int candidate;
	vec3_t candidate_origin, virtualorigin;
	float mindist = 0;

	if( ent->flags & FL_TEAMSLAVE )
		return NODE_INVALID;

	plat_dist = ent->moveinfo.start_origin[2] - ent->moveinfo.end_origin[2];
	platlip = ( ent->r.maxs[2] - ent->r.mins[2] ) - plat_dist;

	//find a good candidate for lower
	candidate_origin[0] = ( ent->r.maxs[0] - ent->r.mins[0] ) / 2 + ent->r.mins[0];
	candidate_origin[1] = ( ent->r.maxs[1] - ent->r.mins[1] ) / 2 + ent->r.mins[1];
	candidate_origin[2] = ent->r.mins[2] + platlip;

	//try to find the closer reachable node to the bottom of the plat
	do
	{
		candidate = AI_FindClosestNode( candidate_origin, mindist, NODE_DENSITY * 2, NODE_ALL );
		if( candidate != NODE_INVALID )
		{
			mindist = DistanceFast( candidate_origin, nodes[candidate].origin );

			//check to see if it would be valid
			if( fabs( candidate_origin[2] - nodes[candidate].origin[2] )
			   < ( fabs( platlip ) + AI_JUMPABLE_HEIGHT ) )
			{
				//put at linkable candidate height
				virtualorigin[0] = candidate_origin[0];
				virtualorigin[1] = candidate_origin[1];
				virtualorigin[2] = nodes[candidate].origin[2];

				G_Trace( &trace, virtualorigin, vec3_origin, vec3_origin, nodes[candidate].origin, ent, MASK_NODESOLID );
				//trace = gi.trace( virtualorigin, vec3_origin, vec3_origin, nodes[candidate].origin, ent, MASK_NODESOLID );
				if( trace.fraction == 1.0 && !trace.startsolid )
				{
#ifdef SHOW_JUMPAD_GUESS
					AI_JumpadGuess_ShowPoint( virtualorigin, "models/objects/grenade/tris.md2" );
#endif
					return candidate;
				}
			}
		}
	}
	while( candidate != NODE_INVALID && numtries++ < maxtries );

	return NODE_INVALID;
}
Esempio n. 17
0
/*
* G_Client_DeadView
*/
static void G_Client_DeadView( edict_t *ent )
{
	edict_t	*body;
	gclient_t *client;
	trace_t	trace;

	client = ent->r.client;

	// find the body
	for( body = game.edicts + gs.maxclients; ENTNUM( body ) < gs.maxclients + BODY_QUEUE_SIZE + 1; body++ )
	{
		if( !body->r.inuse || body->r.svflags & SVF_NOCLIENT )
			continue;
		if( body->activator == ent )  // this is our body
			break;
	}

	if( body->activator != ent )
	{                          // ran all the list and didn't find our body
		return;
	}

	// move us to body position
	VectorCopy( body->s.origin, ent->s.origin );
	VectorCopy( body->s.origin, ent->s.old_origin );
	ent->s.teleported = qtrue;
	client->ps.viewangles[ROLL] = 0;
	client->ps.viewangles[PITCH] = 0;

	// see if our killer is still in view
	if( body->enemy && ( body->enemy != ent ) )
	{
		G_Trace( &trace, ent->s.origin, vec3_origin, vec3_origin, body->enemy->s.origin, body, MASK_OPAQUE );
		if( trace.fraction != 1.0f )
		{
			body->enemy = NULL;
		}
		else
		{
			client->ps.viewangles[YAW] = LookAtKillerYAW( ent, NULL, body->enemy );
		}
	}
	else
	{    // nobody killed us, so just circle around the body ?

	}

	G_ProjectThirdPersonView( ent->s.origin, client->ps.viewangles, body );
	VectorCopy( client->ps.viewangles, ent->s.angles );
	VectorCopy( ent->s.origin, client->ps.pmove.origin );
	VectorClear( client->ps.pmove.velocity );

	GS_SnapPosition( client->ps.pmove.origin, ent->r.mins, ent->r.maxs, ENTNUM( ent ), 0 );
}
Esempio n. 18
0
//==========================================
// AI_CheckEyes
// Helper for ACEMV_SpecialMove.
// Tries to turn when in front of obstacle
//==========================================
static qboolean AI_CheckEyes( edict_t *self, usercmd_t *ucmd )
{
	vec3_t forward, right;
	vec3_t leftstart, rightstart, focalpoint;
	vec3_t dir, offset;
	trace_t traceRight;
	trace_t traceLeft;

	// Get current angle and set up "eyes"
	VectorCopy( self->s.angles, dir );
	AngleVectors( dir, forward, right, NULL );

	if( !self->movetarget )
		VectorSet( offset, 200, 0, self->r.maxs[2]*0.5 ); // focalpoint
	else
		VectorSet( offset, 64, 0, self->r.maxs[2]*0.5 ); // wander focalpoint

	G_ProjectSource( self->s.origin, offset, forward, right, focalpoint );

	VectorSet( offset, 0, 18, self->r.maxs[2]*0.5 );
	G_ProjectSource( self->s.origin, offset, forward, right, leftstart );
	offset[1] -= 36;
	G_ProjectSource( self->s.origin, offset, forward, right, rightstart );

	G_Trace( &traceRight, rightstart, NULL, NULL, focalpoint, self, MASK_AISOLID );
	G_Trace( &traceLeft, leftstart, NULL, NULL, focalpoint, self, MASK_AISOLID );

	// Find the side with more open space and turn
	if( traceRight.fraction != 1 || traceLeft.fraction != 1 )
	{
		if( traceRight.fraction > traceLeft.fraction )
			self->s.angles[YAW] += ( 1.0 - traceLeft.fraction ) * 45.0;
		else
			self->s.angles[YAW] += -( 1.0 - traceRight.fraction ) * 45.0;

		ucmd->forwardmove = 1;
		return qtrue;
	}

	return qfalse;
}
Esempio n. 19
0
static unsigned int G_FindPointedPlayer( edict_t *self ) {
	trace_t trace;
	int i, j, bestNum = 0;
	vec3_t boxpoints[8];
	float value, dist, value_best = 0.90f;   // if nothing better is found, print nothing
	edict_t *other;
	vec3_t vieworg, dir, viewforward;

	if( G_IsDead( self ) ) {
		return 0;
	}

	// we can't handle the thirdperson modifications in server side :/
	VectorSet( vieworg, self->r.client->ps.pmove.origin[0], self->r.client->ps.pmove.origin[1], self->r.client->ps.pmove.origin[2] + self->r.client->ps.viewheight );
	AngleVectors( self->r.client->ps.viewangles, viewforward, NULL, NULL );

	for( i = 0; i < gs.maxclients; i++ ) {
		other = PLAYERENT( i );
		if( !other->r.inuse ) {
			continue;
		}
		if( !other->r.client ) {
			continue;
		}
		if( other == self ) {
			continue;
		}
		if( !other->r.solid || ( other->r.svflags & SVF_NOCLIENT ) ) {
			continue;
		}

		VectorSubtract( other->s.origin, self->s.origin, dir );
		dist = VectorNormalize2( dir, dir );
		if( dist > 1000 ) {
			continue;
		}

		value = DotProduct( dir, viewforward );

		if( value > value_best ) {
			BuildBoxPoints( boxpoints, other->s.origin, tv( 4, 4, 4 ), tv( 4, 4, 4 ) );
			for( j = 0; j < 8; j++ ) {
				G_Trace( &trace, vieworg, vec3_origin, vec3_origin, boxpoints[j], self, MASK_SHOT | MASK_OPAQUE );
				if( trace.ent && trace.ent == ENTNUM( other ) ) {
					value_best = value;
					bestNum = ENTNUM( other );
				}
			}
		}
	}

	return bestNum;
}
Esempio n. 20
0
/**
 * @todo Use this function to enable footsteps over network
 * @note Only play the water sounds if actor is not in STATE_CROUCHED mode
 * we can assume, that moving slower and more carefully would also not produce
 * the water sounds
 */
void G_PhysicsStep (edict_t *ent)
{
	/**
	 * @todo don't play foot step sounds for flying units.
	 */
	if (ent->moveinfo.currentStep < ent->moveinfo.steps) {
		const int contentFlags = ent->contentFlags;
		const vismask_t visflags = ent->moveinfo.visflags[ent->moveinfo.currentStep];
		/* Send the sound effect to everyone how's not seeing the actor */
		if (!G_IsCrouched(ent)) {
			if (contentFlags & CONTENTS_WATER) {
				if (ent->moveinfo.contentFlags[ent->moveinfo.currentStep] & CONTENTS_WATER) {
					/* looks like we already are in the water */
					/* send water moving sound */
					G_EventSpawnSound(~G_VisToPM(visflags), true, ent, ent->origin, "footsteps/water_under");
				} else {
					/* send water entering sound */
					G_EventSpawnSound(~G_VisToPM(visflags), true, ent, ent->origin, "footsteps/water_in");
				}
			} else if (ent->contentFlags & CONTENTS_WATER) {
				/* send water leaving sound */
				G_EventSpawnSound(~G_VisToPM(visflags), true, ent, ent->origin, "footsteps/water_out");
			} else {
				trace_t trace;
				vec3_t from, to;

				VectorCopy(ent->origin, to);
				VectorCopy(ent->origin, from);
				/* we should really hit the ground with this */
				to[2] -= UNIT_HEIGHT;

				trace = G_Trace(from, to, NULL, MASK_SOLID);
				if (trace.surface) {
					const char *snd = gi.GetFootstepSound(trace.surface->name);
					if (snd)
						G_EventSpawnSound(~G_VisToPM(visflags), true, ent, ent->origin, snd);
				}
			}
		}

		/* and now save the new contents */
		ent->contentFlags = ent->moveinfo.contentFlags[ent->moveinfo.currentStep];
		ent->moveinfo.currentStep++;

		/* Immediately re-think */
		ent->nextthink = (level.framenum + 3) * SERVER_FRAME_SECONDS;
	} else {
		ent->moveinfo.currentStep = 0;
		ent->moveinfo.steps = 0;
		ent->think = NULL;
	}
}
bool TacticalSpotsDetector::LooksLikeACoverArea(const aas_area_t &area, const OriginParams &originParams, 
                                                const CoverProblemParams &problemParams)
{
    edict_t *passent = const_cast<edict_t *>(problemParams.attackerEntity);
    float *attackerOrigin = const_cast<float *>(problemParams.attackerOrigin);
    float *areaCenter = const_cast<float *>(area.center);
    const edict_t *doNotHitEntity = originParams.originEntity;

    trace_t trace;
    G_Trace(&trace, attackerOrigin, nullptr, nullptr, areaCenter, passent, MASK_AISOLID);
    if (trace.fraction == 1.0f)
        return false;

    float harmfulRayThickness = problemParams.harmfulRayThickness;

    vec3_t bounds[2] =
    {
        { -harmfulRayThickness, -harmfulRayThickness, -harmfulRayThickness },
        { +harmfulRayThickness, +harmfulRayThickness, +harmfulRayThickness }
    };

    // Convert bounds from relative to absolute
    VectorAdd(bounds[0], area.center, bounds[0]);
    VectorAdd(bounds[1], area.center, bounds[1]);

    for (int i = 0; i < 8; ++i)
    {
        vec3_t traceEnd;
        traceEnd[0] = bounds[(i >> 2) & 1][0];
        traceEnd[1] = bounds[(i >> 1) & 1][1];
        traceEnd[2] = bounds[(i >> 0) & 1][2];
        G_Trace(&trace, attackerOrigin, nullptr, nullptr, traceEnd, passent, MASK_AISOLID);
        if (trace.fraction == 1.0f || game.edicts + trace.ent == doNotHitEntity)
            return false;
    }

    return true;
}
Esempio n. 22
0
/*
* AI_DropNodeOriginToFloor
*/
qboolean AI_DropNodeOriginToFloor( vec3_t origin, edict_t *passent )
{
	trace_t	trace;

	G_Trace( &trace, origin, tv( item_box_mins[0], item_box_mins[1], 0 ), tv( item_box_maxs[0], item_box_maxs[1], 0 ), tv( origin[0], origin[1], world->r.mins[2] ), passent, MASK_NODESOLID );
	if( trace.startsolid )
		return qfalse;

	origin[0] = trace.endpos[0];
	origin[1] = trace.endpos[1];
	origin[2] = trace.endpos[2] + 2 + abs( playerbox_stand_mins[2] );

	return qtrue;
}
Esempio n. 23
0
void AiEntityPhysicsState::UpdateAreaNums() {
	const AiAasWorld *aasWorld = AiAasWorld::Instance();
	this->currAasAreaNum = ( decltype( this->currAasAreaNum ) )aasWorld->FindAreaNum( Origin() );
	// Use a computation shortcut when entity is on ground
	if( this->groundEntNum >= 0 ) {
		this->droppedToFloorOriginOffset = ( decltype( this->droppedToFloorOriginOffset ) )( -playerbox_stand_mins[2] );
		this->droppedToFloorOriginOffset += 4.0f;
		SetHeightOverGround( 0 );
		Vec3 droppedOrigin( Origin() );
		droppedOrigin.Z() -= this->droppedToFloorOriginOffset;
		this->droppedToFloorAasAreaNum = ( decltype( this->droppedToFloorAasAreaNum ) )aasWorld->FindAreaNum( droppedOrigin );
		return;
	}

	// Use a computation shortcut when the current area is grounded
	if( aasWorld->AreaSettings()[this->currAasAreaNum].areaflags & AREA_GROUNDED ) {
		float areaMinsZ = aasWorld->Areas()[this->currAasAreaNum].mins[2];
		float selfZ = Self()->s.origin[2];
		float heightOverGround_ = selfZ - areaMinsZ + playerbox_stand_maxs[2];
		clamp_high( heightOverGround_, GROUND_TRACE_DEPTH );
		SetHeightOverGround( heightOverGround_ );
		this->droppedToFloorOriginOffset = ( decltype( this->droppedToFloorOriginOffset ) )( heightOverGround_ - 4.0f );
		this->droppedToFloorAasAreaNum = this->currAasAreaNum;
		return;
	}

	// Try drop an origin from air to floor
	trace_t trace;
	edict_t *ent = const_cast<edict_t *>( Self() );
	Vec3 traceEnd( Origin() );
	traceEnd.Z() -= GROUND_TRACE_DEPTH;
	G_Trace( &trace, this->origin, ent->r.mins, ent->r.maxs, traceEnd.Data(), ent, MASK_PLAYERSOLID );
	// Check not only whether there is a hit but test whether is it really a ground (and not a wall or obstacle)
	if( trace.fraction != 1.0f && Origin()[2] - trace.endpos[2] > -playerbox_stand_mins[2] ) {
		float heightOverGround_ = trace.fraction * GROUND_TRACE_DEPTH + playerbox_stand_mins[2];
		this->droppedToFloorOriginOffset = ( decltype( this->droppedToFloorOriginOffset ) )( -playerbox_stand_mins[2] );
		this->droppedToFloorOriginOffset -= heightOverGround_ - 4.0f;
		SetHeightOverGround( heightOverGround_ );
		Vec3 droppedOrigin( Origin() );
		droppedOrigin.Z() -= this->droppedToFloorOriginOffset;
		this->droppedToFloorAasAreaNum = ( decltype( this->droppedToFloorAasAreaNum ) )aasWorld->FindAreaNum( droppedOrigin );
		return;
	}

	this->droppedToFloorOriginOffset = 0;
	SetHeightOverGround( std::numeric_limits<float>::infinity() );
	this->droppedToFloorAasAreaNum = this->currAasAreaNum;
}
Esempio n. 24
0
qboolean AI_visible( edict_t *self, edict_t *other )
{
	vec3_t spot1;
	vec3_t spot2;
	trace_t	trace;

	VectorCopy( self->s.origin, spot1 );
	spot1[2] += self->viewheight;
	VectorCopy( other->s.origin, spot2 );
	spot2[2] += other->viewheight;
	G_Trace( &trace, spot1, vec3_origin, vec3_origin, spot2, self, MASK_OPAQUE );

	if( trace.fraction == 1.0 )
		return qtrue;
	return qfalse;
}
Esempio n. 25
0
//==========================================
// AI_ItemIsReachable
// Can we get there? Jalfixme: this needs better checks a lot
//==========================================
qboolean AI_ShortRangeReachable( edict_t *self, vec3_t goal )
{
	trace_t trace;
	vec3_t v;

	VectorCopy( self->r.mins, v );
	v[2] += AI_STEPSIZE;

	G_Trace( &trace, self->s.origin, v, self->r.maxs, goal, self, MASK_NODESOLID );
	//trace = gi.trace ( self->s.origin, v, self->maxs, goal, self, MASK_NODESOLID );

	// Yes we can see it
	if( trace.fraction == 1.0 )
		return qtrue;
	else
		return qfalse;
}
Esempio n. 26
0
//===================
//  AI_IsStep
//  Checks the floor one step below the player. Used to detect
//  if the player is really falling or just walking down a stair.
//===================
qboolean AI_IsStep( edict_t *ent )
{
	vec3_t point;
	trace_t	trace;

	//determine a point below
	point[0] = ent->s.origin[0];
	point[1] = ent->s.origin[1];
	point[2] = ent->s.origin[2] - ( 1.6*AI_STEPSIZE );

	//trace to point
	G_Trace( &trace, ent->s.origin, ent->r.mins, ent->r.maxs, point, ent, MASK_PLAYERSOLID );

	if( !ISWALKABLEPLANE( &trace.plane ) && !trace.startsolid )
		return qfalse;

	//found solid.
	return qtrue;
}
Esempio n. 27
0
//==========================================
// BOT_DMclass_PredictProjectileShot
// predict target movement
//==========================================
static void BOT_DMclass_PredictProjectileShot( edict_t *self, vec3_t fire_origin, float projectile_speed, vec3_t target, vec3_t target_velocity )
{
	vec3_t predictedTarget;
	vec3_t targetMovedir;
	float targetSpeed;
	float predictionTime;
	float distance;
	trace_t	trace;
	int contents;

	if( projectile_speed <= 0.0f )
		return;

	targetSpeed = VectorNormalize2( target_velocity, targetMovedir );

	// ok, this is not going to be 100% precise, since we will find the
	// time our projectile will take to travel to enemy's CURRENT position,
	// and them find enemy's position given his CURRENT velocity and his CURRENT dir
	// after prediction time. The result will be much better if the player
	// is moving to the sides (relative to us) than in depth (relative to us).
	// And, of course, when the player moves in a curve upwards it will totally miss (ie, jumping).

	// but in general it does a great job, much better than any human player :)

	distance = DistanceFast( fire_origin, target );
	predictionTime = distance/projectile_speed;
	VectorMA( target, predictionTime*targetSpeed, targetMovedir, predictedTarget );

	// if this position is inside solid, try finding a position at half of the prediction time
	contents = G_PointContents( predictedTarget );
	if( contents & CONTENTS_SOLID && !( contents & CONTENTS_PLAYERCLIP ) )
	{
		VectorMA( target, ( predictionTime * 0.5f )*targetSpeed, targetMovedir, predictedTarget );
		contents = G_PointContents( predictedTarget );
		if( contents & CONTENTS_SOLID && !( contents & CONTENTS_PLAYERCLIP ) )
			return; // INVALID
	}

	// if we can see this point, we use it, otherwise we keep the current position
	G_Trace( &trace, fire_origin, vec3_origin, vec3_origin, predictedTarget, self, MASK_SHOT );
	if( trace.fraction == 1.0f || ( trace.ent && game.edicts[trace.ent].takedamage ) )
		VectorCopy( predictedTarget, target );
}
qboolean SensoryPerception::isInLineOfSight( const Vector &position , const int entNum )
{
  auto startPos = act->origin;
	startPos.z += 15;
	
	auto endPos = position;
	endPos.z += 15;
	
	Vector modMins;
	Vector modMaxs;
	
	modMins = act->mins;
	modMins *= 1.5;
	
	modMaxs = act->maxs;
	modMaxs *= 1.5;
	
	auto trace = G_Trace( startPos, modMins, modMaxs, endPos, act, act->edict->clipmask, false, "isInLineOfSight" );
	//G_DebugLine( startPos , trace.endpos, 1.0f, 0.0f, 1.0f, 1.0f );
	
	_lineOfSight.entNum = entNum;
	_lineOfSight.time   = level.time;
	
	if ( trace.entityNum == entNum || entNum == ENTITYNUM_NONE )
	{
		_lineOfSight.inLineOfSight = true;      
	}
	else
	{
		auto traceEnt = G_GetEntity( trace.entityNum );
		_lineOfSight.inLineOfSight = false;
		
		if ( traceEnt && traceEnt->isSubclassOf( Actor) )
		{
			Actor *traceActor;
			traceActor = dynamic_cast<Actor*>(traceEnt);
			
			_lineOfSight.inLineOfSight = traceActor->sensoryPerception->checkInLineOfSight( position , entNum );
		}            
	}
	
	return _lineOfSight.inLineOfSight;
}
Esempio n. 29
0
int AI_FindClosestReachableNode( vec3_t origin, edict_t *passent, int range, unsigned int flagsmask )
{
	int i;
	float closest;
	float dist;
	int node = -1;
	trace_t	tr;
	vec3_t maxs, mins;

	VectorSet( mins, -8, -8, -8 );
	VectorSet( maxs, 8, 8, 8 );

	// For Ladders, do not worry so much about reachability
	if( flagsmask & NODEFLAGS_LADDER )
	{
		VectorCopy( vec3_origin, maxs );
		VectorCopy( vec3_origin, mins );
	}

	closest = range;

	for( i = 0; i < nav.num_nodes; i++ )
	{
		if( flagsmask == NODE_ALL || nodes[i].flags & flagsmask )
		{
			dist = DistanceFast( nodes[i].origin, origin );

			if( dist < closest )
			{
				// make sure it is visible
				G_Trace( &tr, origin, mins, maxs, nodes[i].origin, passent, MASK_NODESOLID );
				if( tr.fraction == 1.0 )
				{
					node = i;
					closest = dist;
				}
			}
		}
	}
	return node;
}
Esempio n. 30
0
/*
* G_Teleport
* 
* Teleports client to specified position
* If client is not spectator teleporting is only done if position is free and teleport effects are drawn.
*/
static bool G_Teleport( edict_t *ent, vec3_t origin, vec3_t angles )
{
	int i;

	if( !ent->r.inuse || !ent->r.client )
		return false;

	if( ent->r.client->ps.pmove.pm_type != PM_SPECTATOR )
	{
		trace_t	tr;

		G_Trace( &tr, origin, ent->r.mins, ent->r.maxs, origin, ent, MASK_PLAYERSOLID );
		if( tr.fraction != 1.0f || tr.startsolid )
			return false;

		G_TeleportEffect( ent, false );
	}

	VectorCopy( origin, ent->s.origin );
	VectorCopy( origin, ent->s.old_origin );
	VectorCopy( origin, ent->olds.origin );
	ent->s.teleported = qtrue;

	VectorClear( ent->velocity );
	ent->r.client->ps.pmove.pm_time = 1;
	ent->r.client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT;

	if( ent->r.client->ps.pmove.pm_type != PM_SPECTATOR )
		G_TeleportEffect( ent, true );

	// set angles
	VectorCopy( angles, ent->s.angles );
	VectorCopy( angles, ent->r.client->ps.viewangles );

	// set the delta angle
	for( i = 0; i < 3; i++ )
		ent->r.client->ps.pmove.delta_angles[i] = ANGLE2SHORT( ent->r.client->ps.viewangles[i] ) - ent->r.client->ucmd.angles[i];

	return true;
}