Esempio n. 1
0
/*
-------------------------
NPC_CheckSightEvents
-------------------------
*/
static int G_CheckSightEvents( gentity_t *self, int hFOV, int vFOV, float maxSeeDist, int ignoreAlert, qboolean mustHaveOwner, int minAlertLevel )
{
	int	bestEvent = -1;
	int bestAlert = -1;
	int	bestTime = -1;
	float	dist, radius;

	maxSeeDist *= maxSeeDist;
	for ( int i = 0; i < level.numAlertEvents; i++ )
	{
		//are we purposely ignoring this alert?
		if ( level.alertEvents[i].ID == ignoreAlert )
			continue;
		//We're only concerned about sounds
		if ( level.alertEvents[i].type != AET_SIGHT )
			continue;
		//must be at least this noticable
		if ( level.alertEvents[i].level < minAlertLevel )
			continue;
		//must have an owner?
		if ( mustHaveOwner && !level.alertEvents[i].owner )
			continue;

		//Must be within range
		dist = DistanceSquared( level.alertEvents[i].position, self->currentOrigin );

		//can't see it
		if ( dist > maxSeeDist )
			continue;

		radius = level.alertEvents[i].radius * level.alertEvents[i].radius;
		if ( dist > radius )
			continue;

		//Must be visible
		if ( InFOV( level.alertEvents[i].position, self, hFOV, vFOV ) == qfalse )
			continue;

		if ( G_ClearLOS( self, level.alertEvents[i].position ) == qfalse )
			continue;

		//FIXME: possibly have the light level at this point affect the
		//			visibility/alert level of this event?  Would also
		//			need to take into account how bright the event
		//			itself is.  A lightsaber would stand out more
		//			in the dark... maybe pass in a light level that
		//			is added to the actual light level at this position?

		//See if this one takes precedence over the previous one
		if ( level.alertEvents[i].level >= bestAlert //higher alert level
			|| (level.alertEvents[i].level==bestAlert&&level.alertEvents[i].timestamp >= bestTime) )//same alert level, but this one is newer
		{//NOTE: equal is better because it's later in the array
			bestEvent = i;
			bestAlert = level.alertEvents[i].level;
			bestTime = level.alertEvents[i].timestamp;
		}
	}

	return bestEvent;
}
Esempio n. 2
0
//Entity to position
qboolean G_ClearLOS( gentity_t *self, gentity_t *ent, const vec3_t end )
{
	vec3_t	eyes;

	CalcEntitySpot( ent, SPOT_HEAD_LEAN, eyes );

	return G_ClearLOS( self, eyes, end );
}
Esempio n. 3
0
//NPC's eyes to position
qboolean G_ClearLOS( gentity_t *self, const vec3_t end )
{
	vec3_t	eyes;

	//Calculate the my position
	CalcEntitySpot( self, SPOT_HEAD_LEAN, eyes );

	return G_ClearLOS( self, eyes, end );
}
Esempio n. 4
0
//Position to entity
qboolean G_ClearLOS( gentity_t *self, const vec3_t start, gentity_t *ent )
{
	vec3_t		spot;

	//Look for the chest first
	CalcEntitySpot( ent, SPOT_ORIGIN, spot );

	if ( G_ClearLOS( self, start, spot ) )
		return qtrue;

	//Look for the head next
	CalcEntitySpot( ent, SPOT_HEAD_LEAN, spot );

	if ( G_ClearLOS( self, start, spot ) )
		return qtrue;

	return qfalse;
}
Esempio n. 5
0
/*
-------------------------
NPC_CheckSoundEvents
-------------------------
*/
static int G_CheckSoundEvents( gentity_t *self, float maxHearDist, int ignoreAlert, qboolean mustHaveOwner, int minAlertLevel )
{
	int	bestEvent = -1;
	int bestAlert = -1;
	int	bestTime = -1;
	float dist, radius;

	maxHearDist *= maxHearDist;

	for ( int i = 0; i < level.numAlertEvents; i++ )
	{
		//are we purposely ignoring this alert?
		if ( i == ignoreAlert )
			continue;
		//We're only concerned about sounds
		if ( level.alertEvents[i].type != AET_SOUND )
			continue;
		//must be at least this noticable
		if ( level.alertEvents[i].level < minAlertLevel )
			continue;
		//must have an owner?
		if ( mustHaveOwner && !level.alertEvents[i].owner )
			continue;
		//Must be within range
		dist = DistanceSquared( level.alertEvents[i].position, self->currentOrigin );

		//can't hear it
		if ( dist > maxHearDist )
			continue;

		radius = level.alertEvents[i].radius * level.alertEvents[i].radius;
		if ( dist > radius )
			continue;

		if ( level.alertEvents[i].addLight )
		{//a quiet sound, must have LOS to hear it
			if ( G_ClearLOS( self, level.alertEvents[i].position ) == qfalse )
			{//no LOS, didn't hear it
				continue;
			}
		}

		//See if this one takes precedence over the previous one
		if ( level.alertEvents[i].level >= bestAlert //higher alert level
			|| (level.alertEvents[i].level==bestAlert&&level.alertEvents[i].timestamp >= bestTime) )//same alert level, but this one is newer
		{//NOTE: equal is better because it's later in the array
			bestEvent = i;
			bestAlert = level.alertEvents[i].level;
			bestTime = level.alertEvents[i].timestamp;
		}
	}

	return bestEvent;
}
Esempio n. 6
0
/*
static void G_DynamicMusicUpdate( usercmd_t *ucmd )

  FIXME: can we merge any of this with the G_ChooseLookEnemy stuff?
*/
static void G_DynamicMusicUpdate( void )
{
	gentity_t	*ent;
	gentity_t	*entityList[MAX_GENTITIES];
	int			numListedEntities;
	vec3_t		mins, maxs;
	int			i, e;
	int			distSq, radius = 2048;
	vec3_t		center;
	int			danger = 0;
	int			battle = 0;
	int			entTeam;
	qboolean	dangerNear = qfalse;
	qboolean	suspicious = qfalse;
	qboolean	LOScalced = qfalse, clearLOS = qfalse;

	//FIXME: intro and/or other cues? (one-shot music sounds)

	//loops

	//player-based
	if ( !player )
	{//WTF?
		player = &g_entities[0];
		return;
	}

	if ( !player->client 
		|| player->client->pers.teamState.state != TEAM_ACTIVE 
		|| level.time - player->client->pers.enterTime < 100 )
	{//player hasn't spawned yet
		return;
	}

	if ( player->health <= 0 && player->max_health > 0 )
	{//defeat music
		if ( level.dmState != DM_DEATH )
		{
			level.dmState = DM_DEATH;
		}
	}

	if ( level.dmState == DM_DEATH )
	{
		gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "death" );
		return;
	}

	if ( level.dmState == DM_BOSS )
	{
		gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "boss" );
		return;
	}

	if ( level.dmState == DM_SILENCE )
	{
		gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "silence" );
		return;
	}

	if ( level.dmBeatTime > level.time )
	{//not on a beat
		return;
	}

	level.dmBeatTime = level.time + 1000;//1 second beats

	if ( player->health <= 20 )
	{
		danger = 1;
	}

	//enemy-based
	VectorCopy( player->currentOrigin, center );
	for ( i = 0 ; i < 3 ; i++ ) 
	{
		mins[i] = center[i] - radius;
		maxs[i] = center[i] + radius;
	}
	
	numListedEntities = gi.EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
	for ( e = 0 ; e < numListedEntities ; e++ ) 
	{
		ent = entityList[ e ];
		if ( !ent || !ent->inuse )
		{
			continue;
		}

		if ( !ent->client || !ent->NPC )
		{
			if ( ent->classname && (!Q_stricmp( "PAS", ent->classname )||!Q_stricmp( "misc_turret", ent->classname )) )
			{//a turret
				entTeam = ent->noDamageTeam;
			}
			else
			{
				continue;
			}
		}
		else
		{//an NPC
			entTeam = ent->client->playerTeam;
		}

		if ( entTeam == player->client->playerTeam )
		{//ally
			continue;
		}

		if ( entTeam == TEAM_NEUTRAL && (!ent->enemy || !ent->enemy->client || ent->enemy->client->playerTeam != player->client->playerTeam) )
		{//a droid that is not mad at me or my allies
			continue;
		}

		if ( !gi.inPVS( player->currentOrigin, ent->currentOrigin ) )
		{//not potentially visible
			continue;
		}

		if ( ent->client && ent->s.weapon == WP_NONE )
		{//they don't have a weapon... FIXME: only do this for droids?
			continue;
		}

		LOScalced = clearLOS = qfalse;
		if ( (ent->enemy==player&&(!ent->NPC||ent->NPC->confusionTime<level.time)) || (ent->client&&ent->client->ps.weaponTime) || (!ent->client&&ent->attackDebounceTime>level.time))
		{//mad
			if ( ent->health > 0 )
			{//alive
				//FIXME: do I really need this check?
				if ( ent->s.weapon == WP_SABER && ent->client && !ent->client->ps.saberActive && ent->enemy != player )
				{//a Jedi who has not yet gotten made at me
					continue;
				}
				if ( ent->NPC && ent->NPC->behaviorState == BS_CINEMATIC )
				{//they're not actually going to do anything about being mad at me...
					continue;
				}
				//okay, they're in my PVS, but how close are they?  Are they actively attacking me?
				if ( !ent->client && ent->s.weapon == WP_TURRET && ent->fly_sound_debounce_time && ent->fly_sound_debounce_time - level.time < 10000 )
				{//a turret that shot at me less than ten seconds ago
				}
				else if ( ent->client && ent->client->ps.lastShotTime && ent->client->ps.lastShotTime - level.time < 10000 )
				{//an NPC that shot at me less than ten seconds ago
				}
				else
				{//not actively attacking me lately, see how far away they are
					distSq = DistanceSquared( ent->currentOrigin, player->currentOrigin );
					if ( distSq > 4194304/*2048*2048*/ )
					{//> 2048 away
						continue;
					}
					else if ( distSq > 1048576/*1024*1024*/ )
					{//> 1024 away
						clearLOS = G_ClearLOS( player, player->client->renderInfo.eyePoint, ent );
						LOScalced = qtrue;
						if ( clearLOS == qfalse )
						{//No LOS
							continue;
						}
					}
				}
				battle++;
			}
		}

		if ( level.dmState == DM_EXPLORE )
		{//only do these visibility checks if you're still in exploration mode
			if ( !InFront( ent->currentOrigin, player->currentOrigin, player->client->ps.viewangles, 0.0f) )
			{//not in front
				continue;
			}

			if ( !LOScalced )
			{
				clearLOS = G_ClearLOS( player, player->client->renderInfo.eyePoint, ent );
			}
			if ( !clearLOS ) 
			{//can't see them directly
				continue;
			}
		}

		if ( ent->health <= 0 )
		{//dead
			if ( !ent->client || level.time - ent->s.time > 10000 )
			{//corpse has been dead for more than 10 seconds
				//FIXME: coming across corpses should cause danger sounds too?
				continue;
			}
		}
		//we see enemies and/or corpses
		danger++;
	}

	if ( !battle )
	{//no active enemies, but look for missiles, shot impacts, etc...
		int alert = G_CheckAlertEvents( player, qtrue, qtrue, 1024, 1024, -1, qfalse, AEL_SUSPICIOUS );
		if ( alert != -1 )
		{//FIXME: maybe tripwires and other FIXED things need their own sound, some kind of danger/caution theme
			if ( G_CheckForDanger( player, alert ) )
			{//found danger near by
				danger++;
				battle = 1;
			}
			else if ( level.alertEvents[alert].owner && (level.alertEvents[alert].owner == player->enemy || (level.alertEvents[alert].owner->client && level.alertEvents[alert].owner->client->playerTeam == player->client->enemyTeam) ) )
			{//NPC on enemy team of player made some noise
				switch ( level.alertEvents[alert].level )
				{
				case AEL_DISCOVERED:
					dangerNear = qtrue;
					break;
				case AEL_SUSPICIOUS:
					suspicious = qtrue;
					break;
				case AEL_MINOR:
					//distraction = qtrue;
					break;
				}
			}
		}
	}

	if ( battle )
	{//battle - this can interrupt level.dmDebounceTime of lower intensity levels
		//play battle
		if ( level.dmState != DM_ACTION )
		{
			gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "action" );
		}
		level.dmState = DM_ACTION;
		if ( battle > 5 )
		{
			//level.dmDebounceTime = level.time + 8000;//don't change again for 5 seconds
		}
		else
		{
			//level.dmDebounceTime = level.time + 3000 + 1000*battle;
		}
	}
	else 
	{
		if ( level.dmDebounceTime > level.time )
		{//not ready to switch yet
			return;
		}
		else
		{//at least 1 second (for beats)
			//level.dmDebounceTime = level.time + 1000;//FIXME: define beat time?
		}
		/*
		if ( danger || dangerNear )
		{//danger
			//stay on whatever we were on, action or exploration
			if ( !danger )
			{//minimum
				danger = 1;
			}
			if ( danger > 3 )
			{
				level.dmDebounceTime = level.time + 5000;
			}
			else
			{
				level.dmDebounceTime = level.time + 2000 + 1000*danger;
			}
		}
		else
		*/
		{//still nothing dangerous going on
			if ( level.dmState != DM_EXPLORE )
			{//just went to explore, hold it for a couple seconds at least
				//level.dmDebounceTime = level.time + 2000;
				gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "explore" );
			}
			level.dmState = DM_EXPLORE;
			//FIXME: look for interest points and play "mysterious" music instead of exploration?
			//FIXME: suspicious and distraction sounds should play some cue or change music in a subtle way?
			//play exploration
		}
		//FIXME: when do we go to silence?
	}
}
Esempio n. 7
0
qboolean NPC_ClearLOS( const vec3_t start, const vec3_t end )
{
	return G_ClearLOS( NPC, start, end );
}