Example #1
0
/*
-------------------------
Howler_Patrol
-------------------------
*/
static void Howler_Patrol( void )
{
	NPCInfo->localState = LSTATE_CLEAR;

	//If we have somewhere to go, then do that
	if ( UpdateGoal() )
	{
		NPC_Howler_Move( 100 );
	}

	vec3_t dif;
	VectorSubtract( g_entities[0].currentOrigin, NPC->currentOrigin, dif );

	if ( VectorLengthSquared( dif ) < 256 * 256 )
	{
		G_SetEnemy( NPC, &g_entities[0] );
	}

	if ( NPC_CheckEnemyExt( qtrue ) == qfalse )
	{
		Howler_Idle();
		return;
	}

	Howler_Attack( 0.0f, qtrue );
}
Example #2
0
//[CoOp]
//Replaced with SP version
static void Howler_Patrol( void )
{
	gentity_t *ClosestPlayer = FindClosestPlayer(NPC->r.currentOrigin, NPC->client->enemyTeam);

	NPCInfo->localState = LSTATE_CLEAR;

	//If we have somewhere to go, then do that
	if ( UpdateGoal() )
	{
		NPC_Howler_Move( 100 );
	}

	if(ClosestPlayer)
	{//attack enemy players that are close.
		if(Distance(ClosestPlayer->r.currentOrigin, NPC->r.currentOrigin) < 256 * 256)
		{
			G_SetEnemy( NPC, ClosestPlayer );
		}
	}

	if ( NPC_CheckEnemyExt( qtrue ) == qfalse )
	{
		Howler_Idle();
		return;
	}

	Howler_Attack( 0.0f, qtrue );
}
Example #3
0
void target_laser_start (gentity_t *self)
{
	gentity_t *ent;

	self->s.eType = ET_BEAM;

	if (self->target) {
		ent = G_Find (NULL, FOFS(targetname), self->target);
		if (!ent) {
			gi.Printf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target);
		}
		G_SetEnemy( self, ent );
	} else {
		G_SetMovedir (self->s.angles, self->movedir);
	}

	self->e_UseFunc   = useF_target_laser_use;
	self->e_ThinkFunc = thinkF_target_laser_think;

	if ( !self->damage ) {
		self->damage = 1;
	}

	if (self->spawnflags & 1)
		target_laser_on (self);
	else
		target_laser_off (self);
}
Example #4
0
//-----------------------------------------------------
void funcGlassDie( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod,int dFlags,int hitLoc )
{
	vec3_t		verts[4], normal;

	// if a missile is stuck to us, blow it up so we don't look dumb....we could, alternately, just let the missile drop off??
	for ( int i = 0; i < MAX_GENTITIES; i++ )
	{
		if ( g_entities[i].s.groundEntityNum == self->s.number && ( g_entities[i].s.eFlags & EF_MISSILE_STICK ))
		{
			G_Damage( &g_entities[i], self, self, NULL, NULL, 99999, 0, MOD_CRUSH ); //?? MOD?
		}
	}

	// Really naughty cheating.  Put in an EVENT at some point...
	cgi_R_GetBModelVerts( cgs.inlineDrawModel[self->s.modelindex], verts, normal );
	CG_DoGlass( verts, normal, self->pos1, self->pos2, self->splashRadius );

	self->takedamage = qfalse;//stop chain reaction runaway loops

	G_SetEnemy( self, self->enemy );

	//So chunks don't get stuck inside me
	self->s.solid = 0;
	self->contents = 0;
	self->clipmask = 0;
	gi.linkentity(self); 

	if ( self->target && attacker != NULL )
	{
		G_UseTargets( self, attacker );
	}

	gi.AdjustAreaPortalState( self, qtrue );
	G_FreeEntity( self );
}
Example #5
0
qboolean AI_CheckEnemyCollision( gentity_t *ent, qboolean takeEnemy )
{
	if ( ent == NULL )
		return qfalse;

	if ( ent->svFlags & SVF_LOCKEDENEMY )
		return qfalse;

	navInfo_t	info;

	NAV_GetLastMove( info );

	//See if we've hit something
	if ( ( info.blocker ) && ( info.blocker != ent->enemy ) )
	{
		if ( ( info.blocker->client ) && ( info.blocker->client->playerTeam == ent->client->enemyTeam ) )
		{
			if ( takeEnemy )
				G_SetEnemy( ent, info.blocker );

			return qtrue;
		}
	}

	return qfalse;
}
Example #6
0
/*
-------------------------
Howler_Patrol
-------------------------
*/
void Howler_Patrol( void )
{
	vector3 dif;

	NPCInfo->localState = LSTATE_CLEAR;

	//If we have somewhere to go, then do that
	if ( UpdateGoal() )
	{
		ucmd.buttons &= ~BUTTON_WALKING;
		NPC_MoveToGoal( qtrue );
	}
	else
	{
		if ( TIMER_Done( NPC, "patrolTime" ))
		{
			TIMER_Set( NPC, "patrolTime", crandom() * 5000 + 5000 );
		}
	}

	//rwwFIXMEFIXME: Care about all clients, not just client 0
	VectorSubtract( &g_entities[0].r.currentOrigin, &NPC->r.currentOrigin, &dif );

	if ( VectorLengthSquared( &dif ) < 256 * 256 )
	{
		G_SetEnemy( NPC, &g_entities[0] );
	}

	if ( NPC_CheckEnemyExt( qtrue ) == qfalse )
	{
		Howler_Idle();
		return;
	}
}
Example #7
0
/*
-------------------------
Howler_Patrol
-------------------------
*/
void Howler_Patrol( void )
{
	NPCInfo->localState = LSTATE_CLEAR;

	//If we have somewhere to go, then do that
	if ( UpdateGoal() )
	{
		ucmd.buttons &= ~BUTTON_WALKING;
		NPC_MoveToGoal( qtrue );
	}
	else
	{
		if ( TIMER_Done( NPC, "patrolTime" ))
		{
			TIMER_Set( NPC, "patrolTime", crandom() * 5000 + 5000 );
		}
	}

	vec3_t dif;

	VectorSubtract( g_entities[0].currentOrigin, NPC->currentOrigin, dif );

	if ( VectorLengthSquared( dif ) < 256 * 256 )
	{
		G_SetEnemy( NPC, &g_entities[0] );
	}

	if ( NPC_CheckEnemyExt( qtrue ) == qfalse )
	{
		Howler_Idle();
		return;
	}
}
Example #8
0
/*
-------------------------
MineMonster_Patrol
-------------------------
*/
void MineMonster_Patrol( void )
{
	vec3_t dif;

	NPCS.NPCInfo->localState = LSTATE_CLEAR;

	//If we have somewhere to go, then do that
	if ( UpdateGoal() )
	{
		NPCS.ucmd.buttons &= ~BUTTON_WALKING;
		NPC_MoveToGoal( qtrue );
	}
	else
	{
		if ( TIMER_Done( NPCS.NPC, "patrolTime" ))
		{
			TIMER_Set( NPCS.NPC, "patrolTime", Q_flrand(-1.0f, 1.0f) * 5000 + 5000 );
		}
	}

	//rwwFIXMEFIXME: Care about all clients, not just client 0
	//OJKFIXME: clietnum 0
	VectorSubtract( g_entities[0].r.currentOrigin, NPCS.NPC->r.currentOrigin, dif );

	if ( VectorLengthSquared( dif ) < 256 * 256 )
	{
		G_SetEnemy( NPCS.NPC, &g_entities[0] );
	}

	if ( NPC_CheckEnemyExt( qtrue ) == qfalse )
	{
		MineMonster_Idle();
		return;
	}
}
Example #9
0
static qboolean NPC_CheckPlayerDistance( void )
{
	//Make sure we have an enemy
	if ( NPC->enemy == NULL )
		return qfalse;

	//Only do this for non-players
	if ( NPC->enemy->s.number == 0 )
		return qfalse;

	//must be set up to get mad at player
	if ( !NPC->client || NPC->client->enemyTeam != TEAM_PLAYER )
		return qfalse;

	//Must be within our FOV
	if ( InFOV( &g_entities[0], NPC, NPCInfo->stats.hfov, NPCInfo->stats.vfov ) == qfalse )
		return qfalse;

	float	distance = DistanceSquared( NPC->currentOrigin, NPC->enemy->currentOrigin );

	if ( distance > DistanceSquared( NPC->currentOrigin, g_entities[0].currentOrigin ) )
	{
		G_SetEnemy( NPC, &g_entities[0] );
		return qtrue;
	}

	return qfalse;
}
Example #10
0
void NPC_BSStandGuard (void)
{
	//FIXME: Use Snapshot info
	if ( NPC->enemy == NULL )
	{//Possible to pick one up by being shot
		if( random() < 0.5 )
		{
			if(NPC->client->enemyTeam)
			{
				//gentity_t *newenemy = NPC_PickEnemy(NPC, NPC->client->enemyTeam, (NPC->cantHitEnemyCounter < 10), (NPC->client->enemyTeam == NPCTEAM_PLAYER), qtrue);
				gentity_t *newenemy = NPC_PickEnemy();
				//only checks for vis if couldn't hit last enemy
				if(newenemy)
				{
					G_SetEnemy( NPC, newenemy );
				}
			}
		}
	}

	if ( NPC->enemy != NULL )
	{
		if( NPCInfo->tempBehavior == BS_STAND_GUARD )
		{
			NPCInfo->tempBehavior = BS_DEFAULT;
		}
		
		if( NPCInfo->behaviorState == BS_STAND_GUARD )
		{
			NPCInfo->behaviorState = BS_STAND_AND_SHOOT;
		}
	}

	NPC_UpdateAngles( qtrue, qtrue );
}
Example #11
0
/*
-------------------------
MineMonster_Patrol
-------------------------
*/
void MineMonster_Patrol( void )
{
	NPCInfo->localState = LSTATE_CLEAR;

	//If we have somewhere to go, then do that
	if ( UpdateGoal() )
	{
		ucmd.buttons &= ~BUTTON_WALKING;
		NPC_MoveToGoal( qtrue );
	}

	vec3_t dif;
	VectorSubtract( g_entities[0].currentOrigin, NPC->currentOrigin, dif );

	if ( VectorLengthSquared( dif ) < 256 * 256 )
	{
		G_SetEnemy( NPC, &g_entities[0] );
	}

	if ( NPC_CheckEnemyExt( qtrue ) == qfalse )
	{
		MineMonster_Idle();
		return;
	}
}
void NPC_Touch(gentity_t *self, gentity_t *other, trace_t *trace) 
{
	if(!self->NPC)
		return;

	SaveNPCGlobals();
	SetNPCGlobals( self );

	if ( other->client ) 
	{//FIXME:  if pushing against another bot, both ucmd.rightmove = 127???
		//Except if not facing one another...
		if ( other->health > 0 ) 
		{
			NPCInfo->touchedByPlayer = other;
		}

		if ( other == NPCInfo->goalEntity ) 
		{
			NPCInfo->aiFlags |= NPCAI_TOUCHED_GOAL;
		}

		if( !(self->svFlags&SVF_LOCKEDENEMY) && !(self->svFlags&SVF_IGNORE_ENEMIES) && !(other->flags & FL_NOTARGET) )
		{
			if ( self->client->enemyTeam )
			{//See if we bumped into an enemy
				if ( other->client->playerTeam == self->client->enemyTeam )
				{//bumped into an enemy
					//FIXME: should we care about disguise here?
					if( NPCInfo->behaviorState != BS_HUNT_AND_KILL && !NPCInfo->tempBehavior )
					{//MCG - Begin: checking specific BS mode here, this is bad, a HACK
						//FIXME: not medics?
						G_SetEnemy( NPC, other );
		//				NPCInfo->tempBehavior = BS_HUNT_AND_KILL;
					}
				}
			}
		}

		//FIXME: do this if player is moving toward me and with a certain dist?
		/*
		if ( other->s.number == 0 && self->client->playerTeam == other->client->playerTeam )
		{
			VectorAdd( self->s.pushVec, other->client->ps.velocity, self->s.pushVec );
		}
		*/
	}
	else 
	{//FIXME: check for SVF_NONNPC_ENEMY flag here?
		if ( other == NPCInfo->goalEntity ) 
		{
			NPCInfo->aiFlags |= NPCAI_TOUCHED_GOAL;
		}
	}

	RestoreNPCGlobals();
}
qboolean NPC_FindEnemy( qboolean checkAlerts )
{
	gentity_t *newenemy;

	//We're ignoring all enemies for now
	//if( NPC->svFlags & SVF_IGNORE_ENEMIES )
	if (0) //rwwFIXMEFIXME: support for flag
	{
		G_ClearEnemy( NPC );
		return qfalse;
	}

	//we can't pick up any enemies for now
	if( NPCInfo->confusionTime > level.time )
	{
		return qfalse;
	}

	//Don't want a new enemy
	//rwwFIXMEFIXME: support for locked enemy
	//if ( ( ValidEnemy( NPC->enemy ) ) && ( NPC->svFlags & SVF_LOCKEDENEMY ) )
	//	return qtrue;

	//See if the player is closer than our current enemy
	if ( NPC_CheckPlayerDistance() )
	{
		return qtrue;
	}

	//Otherwise, turn off the flag
//	NPC->svFlags &= ~SVF_LOCKEDENEMY;
	//See if the player is closer than our current enemy
	if ( NPC->client->NPC_class != CLASS_RANCOR 
		&& NPC->client->NPC_class != CLASS_WAMPA
		//&& NPC->client->NPC_class != CLASS_SAND_CREATURE
		&& NPC_CheckPlayerDistance() )
	{//rancors, wampas & sand creatures don't care if player is closer, they always go with closest
		return qtrue;
	}

	//If we've gotten here alright, then our target it still valid
	if ( NPC_ValidEnemy( NPC->enemy ) )
		return qtrue;

	newenemy = NPC_PickEnemyExt( checkAlerts );

	//if we found one, take it as the enemy
	if( NPC_ValidEnemy( newenemy ) )
	{
		G_SetEnemy( NPC, newenemy );
		return qtrue;
	}

	return qfalse;
}
Example #14
0
void ammo_use( gentity_t *self, gentity_t *other, gentity_t *activator)
{
	int dif;

	G_ActivateBehavior(self,BSET_USE);

	if (self->think != NULL)
	{
		if (self->use != NULL)
		{
			self->think = NULL;
		}
	}
	else
	{
		if (other->client)
		{
			dif = ammoData[AMMO_BLASTER].max - other->client->ps.ammo[AMMO_BLASTER];
		}
		else
		{	// Being triggered to be used up
			dif = 1;
			self->count = 0;
		}

		// Does player already have full ammo?
		if (dif > 0)
		{
//			G_Sound(self, G_SoundIndex("sound/player/suitenergy.wav") );

			if ((dif >= self->count) || (self->count<1)) // use it all up?
			{
				ammo_shutdown(self);
			}
		}	
		else
		{
//			G_Sound(self, G_SoundIndex("sound/weapons/noammo.wav") );
		}
		// Use target when used
		if (self->spawnflags & 8)
		{
			G_UseTargets( self, activator );	
		}

		self->use = NULL;	
		G_SetEnemy( self, other );
		self->think = ammo_think;
		self->nextthink = level.time + 50;
	}	
}
Example #15
0
void funcBBrushDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod,int dFlags,int hitLoc)
{
	self->takedamage = qfalse;//stop chain reaction runaway loops

	G_SetEnemy(self, attacker);

	if(self->delay)
	{
		self->e_ThinkFunc = thinkF_funcBBrushDieGo;
		self->nextthink = level.time + floor(self->delay * 1000.0f);
		return;
	}

	funcBBrushDieGo(self);
}
Example #16
0
//------------------------------------------
void fx_target_beam_link( gentity_t *ent )
{
	gentity_t	*target = NULL;
	vec3_t		dir;
	float		len;

	target = G_Find( target, FOFS(targetname), ent->target );

	if ( !target )
	{
		Com_Printf( "bolt_link: unable to find target %s\n", ent->target );
		G_FreeEntity( ent );
		return;
	}

	ent->attackDebounceTime = level.time;

	if ( !target->classname || Q_stricmp( "info_null", target->classname ) )
	{//don't want to set enemy to something that's going to free itself... actually, this could be bad in other ways, too... ent pointer could be freed up and re-used by the time we check it next
		G_SetEnemy( ent, target );
	}
	VectorSubtract( target->s.origin, ent->s.origin, dir );//er, does it ever use dir?
	len = VectorNormalize( dir );//er, does it use len or dir?
	vectoangles( dir, ent->s.angles );//er, does it use s.angles?
	
	VectorCopy( target->s.origin, ent->s.origin2 );

	if ( ent->spawnflags & 1 )
	{
		// Do nothing
		ent->e_ThinkFunc	= thinkF_NULL;
	}
	else
	{
		if ( !(ent->spawnflags & 8 )) // one_shot, only calls when used
		{
			// switch think functions to avoid doing the bolt_link every time
			ent->e_ThinkFunc = thinkF_fx_target_beam_think;
			ent->nextthink	= level.time + FRAMETIME;
		}
	}

	ent->e_UseFunc = useF_fx_target_beam_use;
	gi.linkentity( ent );
}
Example #17
0
void TurretG2Pain( gentity_t *self, gentity_t *attacker, int damage ) {
	if ( self->paintarget && self->paintarget[0] ) {
		if ( self->genericValue8 < level.time ) {
			G_UseTargets2( self, self, self->paintarget );
			self->genericValue8 = level.time + self->genericValue4;
		}
	}

	if ( attacker->client && attacker->client->ps.weapon == WP_DEMP2 ) {
		self->attackDebounceTime = level.time + 2000 + random() * 500;
		self->painDebounceTime = self->attackDebounceTime;
	}
	if ( !self->enemy ) {//react to being hit
		G_SetEnemy( self, attacker );
	}
	//self->s.health = self->health;
	//mmm..yes..bad.
}
Example #18
0
qboolean NPC_FindEnemy( qboolean checkAlerts = qfalse )
{
	//We're ignoring all enemies for now
	if( NPC->svFlags & SVF_IGNORE_ENEMIES )
	{
		G_ClearEnemy( NPC );
		return qfalse;
	}

	//we can't pick up any enemies for now
	if( NPCInfo->confusionTime > level.time )
	{
		return qfalse;
	}

	//Don't want a new enemy
	if ( ( ValidEnemy( NPC->enemy ) ) && ( NPC->svFlags & SVF_LOCKEDENEMY ) )
		return qtrue;

	//See if the player is closer than our current enemy
	if ( NPC_CheckPlayerDistance() )
	{
		return qtrue;
	}

	//Otherwise, turn off the flag
	NPC->svFlags &= ~SVF_LOCKEDENEMY;

	//If we've gotten here alright, then our target it still valid
	if ( NPC_ValidEnemy( NPC->enemy ) )
		return qtrue;

	gentity_t *newenemy = NPC_PickEnemyExt( checkAlerts );

	//if we found one, take it as the enemy
	if( NPC_ValidEnemy( newenemy ) )
	{
		G_SetEnemy( NPC, newenemy );
		return qtrue;
	}

	return qfalse;
}
Example #19
0
void target_scriptrunner_use(gentity_t *self, gentity_t *other, gentity_t *activator)
{
	if ( self->nextthink > level.time )
	{
		return;
	}

	self->activator = activator;
	G_SetEnemy( self, other );
	if ( self->delay )
	{//delay before firing scriptrunner
		self->e_ThinkFunc = thinkF_scriptrunner_run;
		self->nextthink = level.time + self->delay;
	}
	else
	{
		scriptrunner_run (self);
	}
}
Example #20
0
void target_relay_use (gentity_t *self, gentity_t *other, gentity_t *activator) 
{
	if ( ( self->spawnflags & 1 ) && activator->client ) 
	{//&& activator->client->ps.persistant[PERS_TEAM] != TEAM_RED ) {
		return;
	}

	if ( ( self->spawnflags & 2 ) && activator->client ) 
	{//&& activator->client->ps.persistant[PERS_TEAM] != TEAM_BLUE ) {
		return;
	}

	if ( self->svFlags & SVF_INACTIVE )
	{//set by target_deactivate
		return;
	}

	if ( self->painDebounceTime > level.time )
	{
		return;
	}

	G_SetEnemy( self, other );
	self->activator = activator;

	if ( self->delay )
	{
		self->e_ThinkFunc = thinkF_target_relay_use_go;
		self->nextthink = level.time + self->delay;
		return;
	}

	target_relay_use_go( self );

	if ( self->wait < 0 )
	{
		self->e_UseFunc = useF_NULL;
	}
	else
	{
		self->painDebounceTime = level.time + self->wait;
	}
}
Example #21
0
//------------------------------------------------------------------------------------------------------------
void TurretPain( gentity_t *self, gentity_t *attacker, int damage )
//------------------------------------------------------------------------------------------------------------
{
	if (self->target_ent)
	{
		self->target_ent->health = self->health;
		if (self->target_ent->maxHealth)
		{
			G_ScaleNetHealth(self->target_ent);
		}
	}

	if ( attacker->client && attacker->client->ps.weapon == WP_DEMP2 )
	{
		self->attackDebounceTime = level.time + 800 + random() * 500;
		self->painDebounceTime = self->attackDebounceTime;
	}
	if ( !self->enemy )
	{//react to being hit
		G_SetEnemy( self, attacker );
	}
}
Example #22
0
void NPC_BSFollowLeader (void)
{
	vec3_t		vec;
	float		leaderDist;
	visibility_t	leaderVis;
	int			curAnim;

	if ( !NPC->client->leader )
	{//ok, stand guard until we find an enemy
		if( NPCInfo->tempBehavior == BS_HUNT_AND_KILL )
		{
			NPCInfo->tempBehavior = BS_DEFAULT;
		}
		else
		{
			NPCInfo->tempBehavior = BS_STAND_GUARD;
			NPC_BSStandGuard();
		}
		return;
	}

	if ( !NPC->enemy  )
	{//no enemy, find one
		NPC_CheckEnemy( NPCInfo->confusionTime<level.time, qfalse );//don't find new enemy if this is tempbehav
		if ( NPC->enemy )
		{//just found one
			NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 3000, 10000 );
		}
		else
		{
			if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
			{
				int eventID = NPC_CheckAlertEvents( qtrue, qtrue );
				if ( level.alertEvents[eventID].level >= AEL_SUSPICIOUS && (NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES) )
				{
					NPCInfo->lastAlertID = level.alertEvents[eventID].ID;
					if ( !level.alertEvents[eventID].owner || 
						!level.alertEvents[eventID].owner->client || 
						level.alertEvents[eventID].owner->health <= 0 ||
						level.alertEvents[eventID].owner->client->playerTeam != NPC->client->enemyTeam )
					{//not an enemy
					}
					else
					{
						//FIXME: what if can't actually see enemy, don't know where he is... should we make them just become very alert and start looking for him?  Or just let combat AI handle this... (act as if you lost him)
						G_SetEnemy( NPC, level.alertEvents[eventID].owner );
						NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 3000, 10000 );
						NPCInfo->enemyLastSeenTime = level.time;
						TIMER_Set( NPC, "attackDelay", Q_irand( 500, 1000 ) );
					}
				}

			}
		}
		if ( !NPC->enemy )
		{
			if ( NPC->client->leader 
				&& NPC->client->leader->enemy 
				&& NPC->client->leader->enemy != NPC
				&& ( (NPC->client->leader->enemy->client&&NPC->client->leader->enemy->client->playerTeam==NPC->client->enemyTeam)
					||(NPC->client->leader->enemy->svFlags&SVF_NONNPC_ENEMY&&NPC->client->leader->enemy->noDamageTeam==NPC->client->enemyTeam) )
				&& NPC->client->leader->enemy->health > 0 )
			{
				G_SetEnemy( NPC, NPC->client->leader->enemy );
				NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 3000, 10000 );
				NPCInfo->enemyLastSeenTime = level.time;
			}
		}
	}
	else 
	{
		if ( NPC->enemy->health <= 0 || (NPC->enemy->flags&FL_NOTARGET) )
		{
			G_ClearEnemy( NPC );
			if ( NPCInfo->enemyCheckDebounceTime > level.time + 1000 )
			{
				NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 1000, 2000 );
			}
		}
		else if ( NPC->client->ps.weapon && NPCInfo->enemyCheckDebounceTime < level.time )
		{
			NPC_CheckEnemy( (NPCInfo->confusionTime<level.time||NPCInfo->tempBehavior!=BS_FOLLOW_LEADER), qfalse );//don't find new enemy if this is tempbehav
		}
	}
	
	if ( NPC->enemy && NPC->client->ps.weapon )
	{//If have an enemy, face him and fire
		if ( NPC->client->ps.weapon == WP_SABER )//|| NPCInfo->confusionTime>level.time )
		{//lightsaber user or charmed enemy
			if ( NPCInfo->tempBehavior != BS_FOLLOW_LEADER )
			{//not already in a temp bState
				//go after the guy
				NPCInfo->tempBehavior = BS_HUNT_AND_KILL;
				NPC_UpdateAngles(qtrue, qtrue);
				return;
			}
		}

		enemyVisibility = NPC_CheckVisibility ( NPC->enemy, CHECK_FOV|CHECK_SHOOT );//CHECK_360|CHECK_PVS|
		if ( enemyVisibility > VIS_PVS )
		{//face
			vec3_t	enemy_org, muzzle, delta, angleToEnemy;
			float	distanceToEnemy;

			CalcEntitySpot( NPC->enemy, SPOT_HEAD, enemy_org );
			NPC_AimWiggle( enemy_org );

			CalcEntitySpot( NPC, SPOT_WEAPON, muzzle );
			
			VectorSubtract( enemy_org, muzzle, delta);
			vectoangles( delta, angleToEnemy );
			distanceToEnemy = VectorNormalize( delta );

			NPCInfo->desiredYaw = angleToEnemy[YAW];
			NPCInfo->desiredPitch = angleToEnemy[PITCH];
			NPC_UpdateFiringAngles( qtrue, qtrue );

			if ( enemyVisibility >= VIS_SHOOT )
			{//shoot
				NPC_AimAdjust( 2 );
				if ( NPC_GetHFOVPercentage( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, NPCInfo->stats.hfov ) > 0.6f 
					&& NPC_GetHFOVPercentage( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, NPCInfo->stats.vfov ) > 0.5f )
				{//actually withing our front cone
					WeaponThink( qtrue );
				}
			}
			else
			{
				NPC_AimAdjust( 1 );
			}
			
			//NPC_CheckCanAttack(1.0, qfalse);
		}
		else
		{
			NPC_AimAdjust( -1 );
		}
	}
	else
	{//FIXME: combine with vector calc below
		vec3_t	head, leaderHead, delta, angleToLeader;

		CalcEntitySpot( NPC->client->leader, SPOT_HEAD, leaderHead );
		CalcEntitySpot( NPC, SPOT_HEAD, head );
		VectorSubtract (leaderHead, head, delta);
		vectoangles ( delta, angleToLeader );
		VectorNormalize(delta);
		NPC->NPC->desiredYaw = angleToLeader[YAW];
		NPC->NPC->desiredPitch = angleToLeader[PITCH];
		
		NPC_UpdateAngles(qtrue, qtrue);
	}

	//leader visible?
	leaderVis = NPC_CheckVisibility( NPC->client->leader, CHECK_PVS|CHECK_360|CHECK_SHOOT );//			ent->e_UseFunc = useF_NULL;


	//Follow leader, stay within visibility and a certain distance, maintain a distance from.
	curAnim = NPC->client->ps.legsAnim;
	if ( curAnim != BOTH_ATTACK1 && curAnim != BOTH_ATTACK2 && curAnim != BOTH_ATTACK3 && curAnim != BOTH_MELEE1 && curAnim != BOTH_MELEE2 )
	{//Don't move toward leader if we're in a full-body attack anim
		//FIXME, use IdealDistance to determine if we need to close distance
		float	followDist = 96.0f;//FIXME:  If there are enmies, make this larger?
		float	backupdist, walkdist, minrundist;

		if ( NPCInfo->followDist )
		{
			followDist = NPCInfo->followDist;
		}
		backupdist = followDist/2.0f;
		walkdist = followDist*0.83;
		minrundist = followDist*1.33;

		VectorSubtract(NPC->client->leader->currentOrigin, NPC->currentOrigin, vec);
		leaderDist = VectorLength( vec );//FIXME: make this just nav distance?
		//never get within their radius horizontally
		vec[2] = 0;
		float leaderHDist = VectorLength( vec );
		if( leaderHDist > backupdist && (leaderVis != VIS_SHOOT || leaderDist > walkdist) )
		{//We should close in?
			NPCInfo->goalEntity = NPC->client->leader;

			NPC_SlideMoveToGoal();
			if ( leaderVis == VIS_SHOOT && leaderDist < minrundist )
			{
				ucmd.buttons |= BUTTON_WALKING;
			}
		}
		else if ( leaderDist < backupdist )
		{//We should back off?
			NPCInfo->goalEntity = NPC->client->leader;
			NPC_SlideMoveToGoal();

			//reversing direction
			ucmd.forwardmove = -ucmd.forwardmove;
			ucmd.rightmove   = -ucmd.rightmove;
			VectorScale( NPC->client->ps.moveDir, -1, NPC->client->ps.moveDir );
		}//otherwise, stay where we are
		//check for do not enter and stop if there's one there...
		if ( ucmd.forwardmove || ucmd.rightmove || VectorCompare( vec3_origin, NPC->client->ps.moveDir ) )
		{
			NPC_MoveDirClear( ucmd.forwardmove, ucmd.rightmove, qtrue );
		}
	}
}
Example #23
0
qboolean NPC_CheckInvestigate( int alertEventNum )
{
	gentity_t	*owner = level.alertEvents[alertEventNum].owner;
	int		invAdd = level.alertEvents[alertEventNum].level;
	vec3_t	soundPos;
	float	soundRad = level.alertEvents[alertEventNum].radius;
	float	earshot = NPCInfo->stats.earshot;

	VectorCopy( level.alertEvents[alertEventNum].position, soundPos );

	//NOTE: Trying to preserve previous investigation behavior
	if ( !owner )
	{
		return qfalse;
	}

	if ( owner->s.eType != ET_PLAYER && owner == NPCInfo->goalEntity ) 
	{
		return qfalse;
	}

	if ( owner->s.eFlags & EF_NODRAW ) 
	{
		return qfalse;
	}

	if ( owner->flags & FL_NOTARGET ) 
	{
		return qfalse;
	}

	if ( soundRad < earshot )
	{
		return qfalse;
	}

	//if(!gi.inPVSIgnorePortals(ent->currentOrigin, NPC->currentOrigin))//should we be able to hear through areaportals?
	if ( !gi.inPVS( soundPos, NPC->currentOrigin ) )
	{//can hear through doors?
		return qfalse;
	}

	if ( owner->client && owner->client->playerTeam && NPC->client->playerTeam && owner->client->playerTeam != NPC->client->playerTeam )
	{
		if( (float)NPCInfo->investigateCount >= (NPCInfo->stats.vigilance*200) && owner )
		{//If investigateCount == 10, just take it as enemy and go
			if ( ValidEnemy( owner ) )
			{//FIXME: run angerscript
				G_SetEnemy( NPC, owner );
				NPCInfo->goalEntity = NPC->enemy;
				NPCInfo->goalRadius = 12;
				NPCInfo->behaviorState = BS_HUNT_AND_KILL;
				return qtrue;
			}
		}
		else
		{
			NPCInfo->investigateCount += invAdd;
		}
		//run awakescript
		G_ActivateBehavior(NPC, BSET_AWAKE);

		/*
		if ( Q_irand(0, 10) > 7 )
		{
			NPC_AngerSound();
		}
		*/

		//NPCInfo->hlookCount = NPCInfo->vlookCount = 0;
		NPCInfo->eventOwner = owner;
		VectorCopy( soundPos, NPCInfo->investigateGoal );
		if ( NPCInfo->investigateCount > 20 )
		{
			NPCInfo->investigateDebounceTime = level.time + 10000;
		}
		else
		{
			NPCInfo->investigateDebounceTime = level.time + (NPCInfo->investigateCount*500);
		}
		NPCInfo->tempBehavior = BS_INVESTIGATE;
		return qtrue;
	}

	return qfalse;
}
Example #24
0
void NPC_StartFlee( gentity_t *enemy, vec3_t dangerPoint, int dangerLevel, int fleeTimeMin, int fleeTimeMax )
{
	if ( Q3_TaskIDPending( NPC, TID_MOVE_NAV ) )
	{//running somewhere that a script requires us to go, don't interrupt that!
		return;
	}

	//if have a fleescript, run that instead
	if ( G_ActivateBehavior( NPC, BSET_FLEE ) )
	{
		return;
	}
	//FIXME: play a flee sound?  Appropriate to situation?
	if ( enemy )
	{
		G_SetEnemy( NPC, enemy );
	}
	
	//FIXME: if don't have a weapon, find nearest one we have a route to and run for it?
	int cp = -1;
	if ( dangerLevel > AEL_DANGER || NPC->s.weapon == WP_NONE || ((!NPCInfo->group || NPCInfo->group->numGroup <= 1) && NPC->health <= 10 ) )
	{//IF either great danger OR I have no weapon OR I'm alone and low on health, THEN try to find a combat point out of PVS
		cp = NPC_FindCombatPoint( NPC->currentOrigin, NPC->currentOrigin, dangerPoint, CP_COVER|CP_AVOID|CP_HAS_ROUTE|CP_NO_PVS, 128 );
	}
	//FIXME: still happens too often...
	if ( cp == -1 )
	{//okay give up on the no PVS thing
		cp = NPC_FindCombatPoint( NPC->currentOrigin, NPC->currentOrigin, dangerPoint, CP_COVER|CP_AVOID|CP_HAS_ROUTE, 128 );
		if ( cp == -1 )
		{//okay give up on the avoid
			cp = NPC_FindCombatPoint( NPC->currentOrigin, NPC->currentOrigin, dangerPoint, CP_COVER|CP_HAS_ROUTE, 128 );
			if ( cp == -1 )
			{//okay give up on the cover
				cp = NPC_FindCombatPoint( NPC->currentOrigin, NPC->currentOrigin, dangerPoint, CP_HAS_ROUTE, 128 );
			}
		}
	}

	//see if we got a valid one
	if ( cp != -1 )
	{//found a combat point
		NPC_SetCombatPoint( cp );
		NPC_SetMoveGoal( NPC, level.combatPoints[cp].origin, 8, qtrue, cp );
		NPCInfo->behaviorState = BS_HUNT_AND_KILL;
		NPCInfo->tempBehavior = BS_DEFAULT;
	}
	else
	{//need to just run like hell!
		if ( NPC->s.weapon != WP_NONE )
		{
			return;//let's just not flee?
		}
		else
		{
			//FIXME: other evasion AI?  Duck?  Strafe?  Dodge?
			NPCInfo->tempBehavior = BS_FLEE;
			//Run straight away from here... FIXME: really want to find farthest waypoint/navgoal from this pos... maybe based on alert event radius?
			NPC_SetMoveGoal( NPC, dangerPoint, 0, qtrue );
			//store the danger point
			VectorCopy( dangerPoint, NPCInfo->investigateGoal );//FIXME: make a new field for this?
		}
	}
	//FIXME: localize this Timer?
	TIMER_Set( NPC, "attackDelay", Q_irand( 500, 2500 ) );
	//FIXME: is this always applicable?
	NPCInfo->squadState = SQUAD_RETREAT;
	TIMER_Set( NPC, "flee", Q_irand( fleeTimeMin, fleeTimeMax ) );
	TIMER_Set( NPC, "panic", Q_irand( 1000, 4000 ) );//how long to wait before trying to nav to a dropped weapon
	TIMER_Set( NPC, "duck", 0 );
}
Example #25
0
/*
-------------------------
NPC_BSRancor_Default
-------------------------
*/
void NPC_BSRancor_Default( void )
{
	AddSightEvent( NPCS.NPC, NPCS.NPC->r.currentOrigin, 1024, AEL_DANGER_GREAT, 50 );

	Rancor_Crush();

	NPCS.NPC->client->ps.eFlags2 &= ~(EF2_USE_ALT_ANIM|EF2_GENERIC_NPC_FLAG);
	if ( NPCS.NPC->count )
	{//holding someone
		NPCS.NPC->client->ps.eFlags2 |= EF2_USE_ALT_ANIM;
		if ( NPCS.NPC->count == 2 )
		{//in my mouth
			NPCS.NPC->client->ps.eFlags2 |= EF2_GENERIC_NPC_FLAG;
		}
	}
	else
	{
		NPCS.NPC->client->ps.eFlags2 &= ~(EF2_USE_ALT_ANIM|EF2_GENERIC_NPC_FLAG);
	}

	if ( TIMER_Done2( NPCS.NPC, "clearGrabbed", qtrue ) )
	{
		Rancor_DropVictim( NPCS.NPC );
	}
	else if ( NPCS.NPC->client->ps.legsAnim == BOTH_PAIN2 
		&& NPCS.NPC->count == 1 
		&& NPCS.NPC->activator )
	{
		if ( !Q_irand( 0, 3 ) )
		{
			Rancor_CheckDropVictim();
		}
	}
	if ( !TIMER_Done( NPCS.NPC, "rageTime" ) )
	{//do nothing but roar first time we see an enemy
		AddSoundEvent( NPCS.NPC, NPCS.NPC->r.currentOrigin, 1024, AEL_DANGER_GREAT, qfalse );//, qfalse );
		NPC_FaceEnemy( qtrue );
		return;
	}
	if ( NPCS.NPC->enemy )
	{
		/*
		if ( NPC->enemy->client //enemy is a client
			&& (NPC->enemy->client->NPC_class == CLASS_UGNAUGHT || NPC->enemy->client->NPC_class == CLASS_JAWA )//enemy is a lowly jawa or ugnaught
			&& NPC->enemy->enemy != NPC//enemy's enemy is not me
			&& (!NPC->enemy->enemy || !NPC->enemy->enemy->client || NPC->enemy->enemy->client->NPC_class!=CLASS_RANCOR) )//enemy's enemy is not a client or is not a rancor (which is as scary as me anyway)
		{//they should be scared of ME and no-one else
			G_SetEnemy( NPC->enemy, NPC );
		}
		*/
		if ( TIMER_Done(NPCS.NPC,"angrynoise") )
		{
			G_Sound( NPCS.NPC, CHAN_AUTO, G_SoundIndex( va("sound/chars/rancor/misc/anger%d.wav", Q_irand(1, 3))) );

			TIMER_Set( NPCS.NPC, "angrynoise", Q_irand( 5000, 10000 ) );
		}
		else
		{
			AddSoundEvent( NPCS.NPC, NPCS.NPC->r.currentOrigin, 512, AEL_DANGER_GREAT, qfalse );//, qfalse );
		}
		if ( NPCS.NPC->count == 2 && NPCS.NPC->client->ps.legsAnim == BOTH_ATTACK3 )
		{//we're still chewing our enemy up
			NPC_UpdateAngles( qtrue, qtrue );
			return;
		}
		//else, if he's in our hand, we eat, else if he's on the ground, we keep attacking his dead body for a while
		if( NPCS.NPC->enemy->client && NPCS.NPC->enemy->client->NPC_class == CLASS_RANCOR )
		{//got mad at another Rancor, look for a valid enemy
			if ( TIMER_Done( NPCS.NPC, "rancorInfight" ) )
			{
				NPC_CheckEnemyExt( qtrue );
			}
		}
		else if ( !NPCS.NPC->count )
		{
			if ( ValidEnemy( NPCS.NPC->enemy ) == qfalse )
			{
				TIMER_Remove( NPCS.NPC, "lookForNewEnemy" );//make them look again right now
				if ( !NPCS.NPC->enemy->inuse || level.time - NPCS.NPC->enemy->s.time > Q_irand( 10000, 15000 ) )
				{//it's been a while since the enemy died, or enemy is completely gone, get bored with him
					NPCS.NPC->enemy = NULL;
					Rancor_Patrol();
					NPC_UpdateAngles( qtrue, qtrue );
					return;
				}
			}
			if ( TIMER_Done( NPCS.NPC, "lookForNewEnemy" ) )
			{
				gentity_t *newEnemy, *sav_enemy = NPCS.NPC->enemy;//FIXME: what about NPC->lastEnemy?
				NPCS.NPC->enemy = NULL;
				newEnemy = NPC_CheckEnemy( NPCS.NPCInfo->confusionTime < level.time, qfalse, qfalse );
				NPCS.NPC->enemy = sav_enemy;
				if ( newEnemy && newEnemy != sav_enemy )
				{//picked up a new enemy!
					NPCS.NPC->lastEnemy = NPCS.NPC->enemy;
					G_SetEnemy( NPCS.NPC, newEnemy );
					//hold this one for at least 5-15 seconds
					TIMER_Set( NPCS.NPC, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
				}
				else
				{//look again in 2-5 secs
					TIMER_Set( NPCS.NPC, "lookForNewEnemy", Q_irand( 2000, 5000 ) );
				}
			}
		}
		Rancor_Combat();
	}
	else 
	{
		if ( TIMER_Done(NPCS.NPC,"idlenoise") )
		{
			G_Sound( NPCS.NPC, CHAN_AUTO, G_SoundIndex( va("sound/chars/rancor/snort_%d.wav", Q_irand(1, 2))) );

			TIMER_Set( NPCS.NPC, "idlenoise", Q_irand( 2000, 4000 ) );
			AddSoundEvent( NPCS.NPC, NPCS.NPC->r.currentOrigin, 384, AEL_DANGER, qfalse );//, qfalse );
		}
		if ( NPCS.NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
		{
			Rancor_Patrol();
		}
		else
		{
			Rancor_Idle();
		}
	}

	NPC_UpdateAngles( qtrue, qtrue );
}
Example #26
0
/*
-------------------------
NPC_Rancor_Pain
-------------------------
*/
void NPC_Rancor_Pain( gentity_t *self, gentity_t *attacker, int damage ) 
{
	qboolean hitByRancor = qfalse;
	if ( attacker&&attacker->client&&attacker->client->NPC_class==CLASS_RANCOR )
	{
		hitByRancor = qtrue;
	}
	if ( attacker 
		&& attacker->inuse 
		&& attacker != self->enemy
		&& !(attacker->flags&FL_NOTARGET) )
	{
		if ( !self->count )
		{
			if ( (!attacker->s.number&&!Q_irand(0,3))
				|| !self->enemy
				|| self->enemy->health == 0
				|| (self->enemy->client&&self->enemy->client->NPC_class == CLASS_RANCOR)
				|| (self->NPC && self->NPC->consecutiveBlockedMoves>=10 && DistanceSquared( attacker->r.currentOrigin, self->r.currentOrigin ) < DistanceSquared( self->enemy->r.currentOrigin, self->r.currentOrigin )) ) 
			{//if my enemy is dead (or attacked by player) and I'm not still holding/eating someone, turn on the attacker
				//FIXME: if can't nav to my enemy, take this guy if I can nav to him
				G_SetEnemy( self, attacker );
				TIMER_Set( self, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
				if ( hitByRancor )
				{//stay mad at this Rancor for 2-5 secs before looking for attacker enemies
					TIMER_Set( self, "rancorInfight", Q_irand( 2000, 5000 ) );
				}

			}
		}
	}
	if ( (hitByRancor|| (self->count==1&&self->activator&&!Q_irand(0,4)) || Q_irand( 0, 200 ) < damage )//hit by rancor, hit while holding live victim, or took a lot of damage
		&& self->client->ps.legsAnim != BOTH_STAND1TO2
		&& TIMER_Done( self, "takingPain" ) )
	{
		if ( !Rancor_CheckRoar( self ) )
		{
			if ( self->client->ps.legsAnim != BOTH_MELEE1
				&& self->client->ps.legsAnim != BOTH_MELEE2
				&& self->client->ps.legsAnim != BOTH_ATTACK2 )
			{//cant interrupt one of the big attack anims
				/*
				if ( self->count != 1 
					|| attacker == self->activator
					|| (self->client->ps.legsAnim != BOTH_ATTACK1&&self->client->ps.legsAnim != BOTH_ATTACK3) )
				*/
				{//if going to bite our victim, only victim can interrupt that anim
					if ( self->health > 100 || hitByRancor )
					{
						TIMER_Remove( self, "attacking" );

						VectorCopy( self->NPC->lastPathAngles, self->s.angles );

						if ( self->count == 1 )
						{
							NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
						}
						else
						{
							NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
						}
						TIMER_Set( self, "takingPain", self->client->ps.legsTimer+Q_irand(0, 500) );

						if ( self->NPC )
						{
							self->NPC->localState = LSTATE_WAITING;
						}
					}
				}
			}
		}
		//let go
		/*
		if ( !Q_irand( 0, 3 ) && self->count == 1 )
		{
			Rancor_DropVictim( self );
		}
		*/
	}
}
Example #27
0
static void NPC_CheckAttacker( gentity_t *other, int mod )
{
	//FIXME: I don't see anything in here that would stop teammates from taking a teammate
	//			as an enemy.  Ideally, there would be code before this to prevent that from
	//			happening, but that is presumptuous.

	//valid ent - FIXME: a VALIDENT macro would be nice here
	if ( !other )
		return;

	if ( other == NPC )
		return;

	if ( !other->inuse )
		return;

	//Don't take a target that doesn't want to be
	if ( other->flags & FL_NOTARGET )
		return;

	if ( NPC->svFlags & SVF_LOCKEDENEMY )
	{//IF LOCKED, CANNOT CHANGE ENEMY!!!!!
		return;
	}

	//If we haven't taken a target, just get mad
	if ( NPC->enemy == NULL )//was using "other", fixed to NPC
	{
		G_SetEnemy( NPC, other );
		return;
	}

	//we have an enemy, see if he's dead
	if ( NPC->enemy->health <= 0 )
	{
		G_ClearEnemy( NPC );
		G_SetEnemy( NPC, other );
		return;
	}

	//Don't take the same enemy again
	if ( other == NPC->enemy )
		return;

	if ( NPC->client->ps.weapon == WP_SABER )
	{//I'm a jedi
		if ( mod == MOD_SABER )
		{//I was hit by a saber  FIXME: what if this was a thrown saber?
			//always switch to this enemy if I'm a jedi and hit by another saber
			G_ClearEnemy( NPC );
			G_SetEnemy( NPC, other );
			return;
		}
	}
	//Special case player interactions
	if ( other == &g_entities[0] )
	{
		//Account for the skill level to skew the results
		float	luckThreshold;

		switch ( g_spskill->integer )
		{
		//Easiest difficulty, mild chance of picking up the player
		case 0:
			luckThreshold = 0.9f;
			break;

		//Medium difficulty, half-half chance of picking up the player
		case 1:
			luckThreshold = 0.5f;
			break;

		//Hardest difficulty, always turn on attacking player
		case 2:
		default:
			luckThreshold = 0.0f;
			break;
		}

		//Randomly pick up the target
		if ( Q_flrand(0.0f, 1.0f) > luckThreshold )
		{
			G_ClearEnemy( other );
			other->enemy = NPC;
		}

		return;
	}
}
Example #28
0
void NPC_Touch(gentity_t *self, gentity_t *other, trace_t *trace)
{
	if(!self->NPC)
		return;

	SaveNPCGlobals();
	SetNPCGlobals( self );

	if ( self->message && self->health <= 0 )
	{//I am dead and carrying a key
		if ( other && player && player->health > 0 && other == player )
		{//player touched me
			char *text;
			qboolean	keyTaken;
			//give him my key
			if ( Q_stricmp( "goodie", self->message ) == 0 )
			{//a goodie key
				if ( (keyTaken = INV_GoodieKeyGive( other )) == qtrue )
				{
					text = "cp @SP_INGAME_TOOK_IMPERIAL_GOODIE_KEY";
					G_AddEvent( other, EV_ITEM_PICKUP, (FindItemForInventory( INV_GOODIE_KEY )-bg_itemlist) );
				}
				else
				{
					text = "cp @SP_INGAME_CANT_CARRY_GOODIE_KEY";
				}
			}
			else
			{//a named security key
				if ( (keyTaken = INV_SecurityKeyGive( player, self->message )) == qtrue )
				{
					text = "cp @SP_INGAME_TOOK_IMPERIAL_SECURITY_KEY";
					G_AddEvent( other, EV_ITEM_PICKUP, (FindItemForInventory( INV_SECURITY_KEY )-bg_itemlist) );
				}
				else
				{
					text = "cp @SP_INGAME_CANT_CARRY_SECURITY_KEY";
				}
			}
			if ( keyTaken )
			{//remove my key
				gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "l_arm_key", 0x00000002 );
				self->message = NULL;
				self->client->ps.eFlags &= ~EF_FORCE_VISIBLE;	//remove sight flag
				G_Sound( player, G_SoundIndex( "sound/weapons/key_pkup.wav" ) );
			}
			gi.SendServerCommand( 0, text );
		}
	}

	if ( other->client )
	{//FIXME:  if pushing against another bot, both ucmd.rightmove = 127???
		//Except if not facing one another...
		if ( other->health > 0 )
		{
			NPCInfo->touchedByPlayer = other;
		}

		if ( other == NPCInfo->goalEntity )
		{
			NPCInfo->aiFlags |= NPCAI_TOUCHED_GOAL;
		}

		if( !(self->svFlags&SVF_LOCKEDENEMY) && !(self->svFlags&SVF_IGNORE_ENEMIES) && !(other->flags & FL_NOTARGET) )
		{
			if ( self->client->enemyTeam )
			{//See if we bumped into an enemy
				if ( other->client->playerTeam == self->client->enemyTeam )
				{//bumped into an enemy
					if( NPCInfo->behaviorState != BS_HUNT_AND_KILL && !NPCInfo->tempBehavior )
					{//MCG - Begin: checking specific BS mode here, this is bad, a HACK
						//FIXME: not medics?
						if ( NPC->enemy != other )
						{//not already mad at them
							G_SetEnemy( NPC, other );
						}
		//				NPCInfo->tempBehavior = BS_HUNT_AND_KILL;
					}
				}
			}
		}

		//FIXME: do this if player is moving toward me and with a certain dist?
		/*
		if ( other->s.number == 0 && self->client->playerTeam == other->client->playerTeam )
		{
			VectorAdd( self->client->pushVec, other->client->ps.velocity, self->client->pushVec );
		}
		*/
	}
	else
	{//FIXME: check for SVF_NONNPC_ENEMY flag here?
		if ( other->health > 0 )
		{
			if ( NPC->enemy == other && (other->svFlags&SVF_NONNPC_ENEMY) )
			{
				NPCInfo->touchedByPlayer = other;
			}
		}

		if ( other == NPCInfo->goalEntity )
		{
			NPCInfo->aiFlags |= NPCAI_TOUCHED_GOAL;
		}
	}

	if ( NPC->client->NPC_class == CLASS_RANCOR )
	{//rancor
		if ( NPCInfo->blockedEntity != other && TIMER_Done(NPC, "blockedEntityIgnore"))
		{//blocked
			//if ( G_EntIsBreakable( other->s.number, NPC ) )
			{//bumped into another breakable, so take that one instead?
				NPCInfo->blockedEntity = other;//???
			}
		}
	}

	RestoreNPCGlobals();
}
Example #29
0
/*
===============
NPC_Pain
===============
*/
void NPC_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, const vec3_t point, int damage, int mod, int hitLoc )
{
	team_t otherTeam = TEAM_FREE;
	int		voiceEvent = -1;

	if ( self->NPC == NULL )
		return;

	if ( other == NULL )
		return;

	//or just remove ->pain in player_die?
	if ( self->client->ps.pm_type == PM_DEAD )
		return;

	if ( other == self )
		return;

	other = G_CheckControlledTurretEnemy(self, other, qfalse);
	if (!other)
	{
		return;
	}

	//MCG: Ignore damage from your own team for now
	if ( other->client )
	{
		otherTeam = other->client->playerTeam;
	//	if ( otherTeam == TEAM_DISGUISE )
	//	{
	//		otherTeam = TEAM_PLAYER;
	//	}
	}

	if ( self->client->playerTeam
		&& other->client
		&& otherTeam == self->client->playerTeam
		&& (!player->client->ps.viewEntity || other->s.number != player->client->ps.viewEntity))
	{//hit by a teammate
		if ( other != self->enemy && self != other->enemy )
		{//we weren't already enemies
			if ( self->enemy || other->enemy
				|| (other->s.number&&other->s.number!=player->client->ps.viewEntity)
				/*|| (!other->s.number&&Q_irand( 0, 3 ))*/ )
			{//if one of us actually has an enemy already, it's okay, just an accident OR wasn't hit by player or someone controlled by player OR player hit ally and didn't get 25% chance of getting mad (FIXME:accumulate anger+base on diff?)
				//FIXME: player should have to do a certain amount of damage to ally or hit them several times to make them mad
				//Still run pain and flee scripts
				if ( self->client && self->NPC )
				{//Run any pain instructions
					if ( self->health <= (self->max_health/3) && G_ActivateBehavior(self, BSET_FLEE) )
					{

					}
					else// if( VALIDSTRING( self->behaviorSet[BSET_PAIN] ) )
					{
						G_ActivateBehavior(self, BSET_PAIN);
					}
				}
				if ( damage != -1 )
				{//-1 == don't play pain anim
					//Set our proper pain animation
					if ( Q_irand( 0, 1 ) )
					{
						NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, EV_FFWARN );
					}
					else
					{
						NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc );
					}
				}
				return;
			}
			else if ( self->NPC && !other->s.number )//should be assumed, but...
			{//dammit, stop that!
				if ( self->NPC->charmedTime > level.time )
				{//mindtricked
					return;
				}
				else if ( self->NPC->ffireCount < 3+((2-g_spskill->integer)*2) )
				{//not mad enough yet
					//Com_Printf( "chck: %d < %d\n", self->NPC->ffireCount, 3+((2-g_spskill->integer)*2) );
					if ( damage != -1 )
					{//-1 == don't play pain anim
						//Set our proper pain animation
						if ( Q_irand( 0, 1 ) )
						{
							NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, EV_FFWARN );
						}
						else
						{
							NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc );
						}
					}
					return;
				}
				else if ( G_ActivateBehavior( self, BSET_FFIRE ) )
				{//we have a specific script to run, so do that instead
					return;
				}
				else
				{//okay, we're going to turn on our ally, we need to set and lock our enemy and put ourselves in a bstate that lets us attack him (and clear any flags that would stop us)
					self->NPC->blockedSpeechDebounceTime = 0;
					voiceEvent = EV_FFTURN;
					self->NPC->behaviorState = self->NPC->tempBehavior = self->NPC->defaultBehavior = BS_DEFAULT;
					other->flags &= ~FL_NOTARGET;
					self->svFlags &= ~(SVF_IGNORE_ENEMIES|SVF_ICARUS_FREEZE|SVF_NO_COMBAT_SOUNDS);
					G_SetEnemy( self, other );
					self->svFlags |= SVF_LOCKEDENEMY;
					self->NPC->scriptFlags &= ~(SCF_DONT_FIRE|SCF_CROUCHED|SCF_WALKING|SCF_NO_COMBAT_TALK|SCF_FORCED_MARCH);
					self->NPC->scriptFlags |= (SCF_CHASE_ENEMIES|SCF_NO_MIND_TRICK);
					//NOTE: we also stop ICARUS altogether
					stop_icarus = qtrue;
					if ( !killPlayerTimer )
					{
						killPlayerTimer = level.time + 10000;
					}
				}
			}
		}
	}

	SaveNPCGlobals();
	SetNPCGlobals( self );

	//Do extra bits
	if ( NPCInfo->ignorePain == qfalse )
	{
		NPCInfo->confusionTime = 0;//clear any charm or confusion, regardless
		if ( NPC->ghoul2.size() && NPC->headBolt != -1 )
		{
			G_StopEffect("force/confusion", NPC->playerModel, NPC->headBolt, NPC->s.number );
		}
		if ( damage != -1 )
		{//-1 == don't play pain anim
			//Set our proper pain animation
			NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, voiceEvent );
		}
		//Check to take a new enemy
		if ( NPC->enemy != other && NPC != other )
		{//not already mad at them
			//if it's an eweb or emplaced gun, get mad at the owner, not the gun
			NPC_CheckAttacker( other, mod );
		}
	}

	//Attempt to run any pain instructions
	if ( self->client && self->NPC )
	{
		//FIXME: This needs better heuristics perhaps
		if(self->health <= (self->max_health/3) && G_ActivateBehavior(self, BSET_FLEE) )
		{
		}
		else //if( VALIDSTRING( self->behaviorSet[BSET_PAIN] ) )
		{
			G_ActivateBehavior(self, BSET_PAIN);
		}
	}

	//Attempt to fire any paintargets we might have
	if( self->paintarget && self->paintarget[0] )
	{
		G_UseTargets2(self, other, self->paintarget);
	}

	if (self->client && self->client->NPC_class==CLASS_BOBAFETT)
	{
		Boba_Pain( self, inflictor, damage, mod);
	}


	RestoreNPCGlobals();
}
Example #30
0
void	Boba_Update()
{
	// Never Forget The Player... Never.
	//-----------------------------------
	if (player && player->inuse && !NPC->enemy)
	{
		G_SetEnemy(NPC, player);
		NPC->svFlags				|= SVF_LOCKEDENEMY;	// Don't forget about the enemy once you've found him
	}

	// Hey, This Is Boba, He Tests The Trace All The Time
	//----------------------------------------------------
	if (NPC->enemy)
	{
		if (!(NPC->svFlags&SVF_NOCLIENT))
		{
			trace_t		testTrace;
			vec3_t		eyes;
			CalcEntitySpot( NPC, SPOT_HEAD_LEAN, eyes );
			gi.trace (&testTrace, eyes, NULL, NULL, NPC->enemy->currentOrigin, NPC->s.number, MASK_SHOT, (EG2_Collision)0, 0);

			bool	wasSeen = Boba_CanSeeEnemy(NPC);

			if (!testTrace.startsolid && 
				!testTrace.allsolid && 
				testTrace.entityNum == NPC->enemy->s.number)
			{
				NPCInfo->enemyLastSeenTime	= level.time;
				NPCInfo->enemyLastHeardTime	= level.time;
				VectorCopy(NPC->enemy->currentOrigin, NPCInfo->enemyLastSeenLocation);
				VectorCopy(NPC->enemy->currentOrigin, NPCInfo->enemyLastHeardLocation);
			}
			else if (gi.inPVS( NPC->enemy->currentOrigin, NPC->currentOrigin))
			{
				NPCInfo->enemyLastHeardTime	= level.time;
				VectorCopy(NPC->enemy->currentOrigin, NPCInfo->enemyLastHeardLocation);
			}

			if (g_bobaDebug->integer)
			{
				bool	nowSeen = Boba_CanSeeEnemy(NPC);
				if (!wasSeen && nowSeen)
				{
					Boba_Printf("Enemy Seen");
				}
				if (wasSeen && !nowSeen)
				{
					Boba_Printf("Enemy Lost");
				}
				CG_DrawEdge(NPC->currentOrigin, NPC->enemy->currentOrigin, (nowSeen)?(EDGE_IMPACT_SAFE):(EDGE_IMPACT_POSSIBLE));
			}
		}

		if (!NPCInfo->surrenderTime)
		{
			if ((level.time - NPCInfo->enemyLastSeenTime)>20000 && TIMER_Done(NPC, "TooLongGoneRespawn"))
			{
				TIMER_Set(NPC, "TooLongGoneRespawn", 30000);	// Give him some time to get to you before trying again
				Boba_Printf("Gone Too Long, Attempting Respawn Even Though Not Hiding");
				Boba_Respawn();
			}
		}
	}


	// Make Sure He Always Appears In The Last Area With Full Health When His Death Script Is Turned On
	//--------------------------------------------------------------------------------------------------
	if (!BobaHadDeathScript && NPC->behaviorSet[BSET_DEATH]!=0)
	{
		if (!gi.inPVS(NPC->enemy->currentOrigin, NPC->currentOrigin))
		{
			Boba_Printf("Attempting Final Battle Spawn...");
			if (Boba_Respawn())
			{
				BobaHadDeathScript = true;
			}
			else
			{
				Boba_Printf("Failed");
			}
		}
	}



	// Don't Forget To Turn Off That Flame Thrower, Mr. Fett - You're Waisting Precious Natural Gases
	//------------------------------------------------------------------------------------------------
	if ((NPCInfo->aiFlags&NPCAI_FLAMETHROW) && (TIMER_Done(NPC, "flameTime")))
	{
		Boba_StopFlameThrower(NPC);
	}


	// Occasionally A Jump Turns Into A Rocket Fly
	//---------------------------------------------
	if ( NPC->client->ps.groundEntityNum == ENTITYNUM_NONE 
		&& NPC->client->ps.forceJumpZStart
		&& !Q_irand( 0, 10 ) )
	{//take off
		Boba_FlyStart( NPC );
	}


	// If Hurting, Try To Run Away
	//-----------------------------
	if (!NPCInfo->surrenderTime && (NPC->health<NPC->max_health/10))
	{
		Boba_Printf("Time To Surrender, Searching For Flee Point");


		// Find The Closest Flee Point That I Can Get To
		//-----------------------------------------------
		int cp = NPC_FindCombatPoint(NPC->currentOrigin, 0, NPC->currentOrigin, CP_FLEE|CP_HAS_ROUTE|CP_TRYFAR|CP_HORZ_DIST_COLL, 0, -1);
		if (cp!=-1)
		{
			NPC_SetCombatPoint( cp );
			NPC_SetMoveGoal( NPC, level.combatPoints[cp].origin, 8, qtrue, cp );
			if (NPC->count<6)
			{
 	 		 	NPCInfo->surrenderTime = level.time + Q_irand(5000, 10000) + 1000*(6-NPC->count);
			}
			else
			{
 	 			NPCInfo->surrenderTime = level.time + Q_irand(5000, 10000);
			}
		}
		else
		{
			Boba_Printf("  Failure");
		}
	}
}