예제 #1
0
//=========================================================
// NoFriendlyFire - checks for possibility of friendly fire
//
// Builds a large box in front of the grunt and checks to see 
// if any squad members are in that box. 
//=========================================================
bool CHL1BaseNPC::NoFriendlyFire( void )
{
	if ( !m_pSquad )
	{
		return true;
	}

	CPlane	backPlane;
	CPlane  leftPlane;
	CPlane	rightPlane;

	Vector	vecLeftSide;
	Vector	vecRightSide;
	Vector	v_left;

	Vector  vForward, vRight, vUp;
	QAngle  vAngleToEnemy;

	if ( GetEnemy() != NULL )
	{
		//!!!BUGBUG - to fix this, the planes must be aligned to where the monster will be firing its gun, not the direction it is facing!!!
		VectorAngles( ( GetEnemy()->WorldSpaceCenter() - GetAbsOrigin() ), vAngleToEnemy );

		AngleVectors ( vAngleToEnemy, &vForward, &vRight, &vUp );
	}
	else
	{
		// if there's no enemy, pretend there's a friendly in the way, so the grunt won't shoot.
		return false;
	}
	
	vecLeftSide = GetAbsOrigin() - ( vRight * ( WorldAlignSize().x * 1.5 ) );
	vecRightSide = GetAbsOrigin() + ( vRight * ( WorldAlignSize().x * 1.5 ) );
	v_left = vRight * -1;

	leftPlane.InitializePlane ( vRight, vecLeftSide );
	rightPlane.InitializePlane ( v_left, vecRightSide );
	backPlane.InitializePlane ( vForward, GetAbsOrigin() );

	AISquadIter_t iter;
	for ( CAI_BaseNPC *pSquadMember = m_pSquad->GetFirstMember( &iter ); pSquadMember; pSquadMember = m_pSquad->GetNextMember( &iter ) )
	{
		if ( pSquadMember == NULL )
			 continue;

		if ( pSquadMember == this )
			 continue;

		if ( backPlane.PointInFront  ( pSquadMember->GetAbsOrigin() ) &&
				 leftPlane.PointInFront  ( pSquadMember->GetAbsOrigin() ) && 
				 rightPlane.PointInFront ( pSquadMember->GetAbsOrigin()) )
			{
				// this guy is in the check volume! Don't shoot!
				return false;
			}
	}

	return true;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_RappelBehavior::CreateZipline()
{
#if 1
	if( !m_hLine )
	{
		int attachment = GetOuter()->LookupAttachment( "zipline" );

		if( attachment != -1 )
		{
			CBeam *pBeam;
			pBeam = CBeam::BeamCreate( "cable/cable.vmt", 1 );
			pBeam->SetColor( 150, 150, 150 );
			pBeam->SetWidth( 0.3 );
			pBeam->SetEndWidth( 0.3 );

			CAI_BaseNPC *pNPC = GetOuter();
			pBeam->PointEntInit( pNPC->GetAbsOrigin() + Vector( 0, 0, 80 ), pNPC );

			pBeam->SetEndAttachment( attachment );

			m_hLine.Set( pBeam );
		}
	}
#endif
}
bool CPhysicsNPCSolver::IsIntersecting()
{
	CAI_BaseNPC *pNPC = m_hNPC.Get();
	CBaseEntity *pPhysics = m_hEntity.Get();
	if ( pNPC && pPhysics )
	{
		Ray_t ray;
		// bloated bounds to force slight separation
		Vector mins = pNPC->WorldAlignMins() - Vector(1,1,1);
		Vector maxs = pNPC->WorldAlignMaxs() + Vector(1,1,1);

		ray.Init( pNPC->GetAbsOrigin(), pNPC->GetAbsOrigin(), mins, maxs );
		trace_t tr;
		enginetrace->ClipRayToEntity( ray, pNPC->PhysicsSolidMaskForEntity(), pPhysics, &tr );
		if ( tr.startsolid )
			return true;
	}
	return false;
}
예제 #4
0
//-----------------------------------------------------------------------------
// Purpose: Gets event from anim stream and throws the object
// Input  :
// Output :
//-----------------------------------------------------------------------------
void CWeaponMolotov::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
{
	switch( pEvent->event )
	{
		case EVENT_WEAPON_THROW:
		{
			CAI_BaseNPC *pNPC	= GetOwner()->MyNPCPointer();
			if (!pNPC)
			{
				return;
			}

			CBaseEntity *pEnemy = pNPC->GetEnemy();
			if (!pEnemy)
			{
				return;
			}

			Vector vec_target = pNPC->GetEnemyLKP();

			// -----------------------------------------------------
			//  Get position of throw
			// -----------------------------------------------------
			// If owner has a hand, set position to the hand bone position
			Vector launchPos;
			int iBIndex = pNPC->LookupBone("Bip01 R Hand");
			if (iBIndex != -1) 
			{
				Vector origin;
				QAngle angles;
				pNPC->GetBonePosition( iBIndex, launchPos, angles);
			}
			// Otherwise just set to in front of the owner
			else 
			{
				Vector vFacingDir = pNPC->BodyDirection2D( );
				vFacingDir = vFacingDir * 60.0; 
				launchPos = pNPC->GetAbsOrigin()+vFacingDir;
			}


			//Vector vecVelocity = VecCheckToss( pNPC, launchPos, vec_target, 1.0 );

			ThrowMolotov( launchPos, m_vecTossVelocity);

			// Drop the weapon and remove as no more ammo
			pNPC->Weapon_Drop( this );
			UTIL_Remove( this );
		}
		break;
		default:
			BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
			break;
	}
}
예제 #5
0
void CAI_PlaneSolver::GenerateObstacleNpcs( const AILocalMoveGoal_t &goal, float probeDist )
{
	if ( !ProbeForNpcs() )
	{
		CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs();
		Vector minsSelf, maxsSelf;
		m_pNpc->CollisionProp()->WorldSpaceSurroundingBounds( &minsSelf, &maxsSelf );
		float radiusSelf = (minsSelf.AsVector2D() - maxsSelf.AsVector2D()).Length() * 0.5;

		for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ )
		{
			CAI_BaseNPC *pAI = ppAIs[i];
			if ( pAI != m_pNpc && pAI->IsAlive() && ( !goal.pPath || pAI != goal.pPath->GetTarget() ) )
			{
				Vector mins, maxs;
				
				pAI->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs );
				if ( mins.z < maxsSelf.z + 12.0 && maxs.z > minsSelf.z - 12.0 )
				{
					float radius = (mins.AsVector2D() - maxs.AsVector2D()).Length() * 0.5;
					float distance = ( pAI->GetAbsOrigin().AsVector2D() - m_pNpc->GetAbsOrigin().AsVector2D() ).Length();
					if ( distance - radius < radiusSelf + probeDist )
					{
						AddObstacle( pAI->WorldSpaceCenter(), radius, pAI, AIMST_AVOID_NPC );
					}
				}
			}
		}

		#ifdef SecobMod__Enable_Fixed_Multiplayer_AI
			CBaseEntity *pPlayer = UTIL_GetNearestPlayer(m_pNpc->GetAbsOrigin()); 
		#else
			CBaseEntity *pPlayer = UTIL_PlayerByIndex( 1 );
		#endif //SecobMod__Enable_Fixed_Multiplayer_AI

		if ( pPlayer )
		{
			Vector mins, maxs;
			
			pPlayer->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs );
			if ( mins.z < maxsSelf.z + 12.0 && maxs.z > minsSelf.z - 12.0 )
			{
				float radius = (mins.AsVector2D() - maxs.AsVector2D()).Length();
				float distance = ( pPlayer->GetAbsOrigin().AsVector2D() - m_pNpc->GetAbsOrigin().AsVector2D() ).Length();
				if ( distance - radius < radiusSelf + probeDist )
				{
					AddObstacle( pPlayer->WorldSpaceCenter(), radius, pPlayer, AIMST_AVOID_NPC );
				}
			}
		}

	}
}
예제 #6
0
void CNPC_Vortigaunt::CallForHelp( char *szClassname, float flDist, CBaseEntity * pEnemy, Vector &vecLocation )
{
    // ALERT( at_aiconsole, "help " );

    // skip ones not on my netname
    if ( !m_pSquad )
        return;

    AISquadIter_t iter;
    for (CAI_BaseNPC *pSquadMember = m_pSquad->GetFirstMember( &iter ); pSquadMember; pSquadMember = m_pSquad->GetNextMember( &iter ) )
    {
        float d = ( GetAbsOrigin() - pSquadMember->GetAbsOrigin() ).Length();

        if ( d < flDist )
        {
            pSquadMember->Remember( bits_MEMORY_PROVOKED );
            pSquadMember->UpdateEnemyMemory( pEnemy, vecLocation );
        }
    }
}
//-----------------------------------------------------------------------------
// Purpose: Check the weapon LOS for an owner at an arbitrary position
//			If bSetConditions is true, LOS related conditions will also be set
//-----------------------------------------------------------------------------
bool CASW_Weapon::WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions )
{
	bool bHasLOS = BaseClass::WeaponLOSCondition(ownerPos, targetPos, bSetConditions);

	// if the weapon has LOS, then do another wider trace to check we don't hit any friendlies
	//   this is to stop the AI marines shooting way too close to other marines, which stops the player thinking about positioning so much
	if (bHasLOS && GetOwner() && asw_weapon_safety_hull.GetFloat() > 0)
	{
		CAI_BaseNPC* npcOwner = GetOwner()->MyNPCPointer();	
		Vector vecRelativeShootPosition;
		VectorSubtract( npcOwner->Weapon_ShootPosition(), npcOwner->GetAbsOrigin(), vecRelativeShootPosition );	// Find its relative shoot position
		Vector barrelPos = ownerPos + vecRelativeShootPosition;	
		CASWWeaponLOSFilter traceFilter( GetOwner(), npcOwner->GetEnemy(), COLLISION_GROUP_BREAKABLE_GLASS );	// Use the custom LOS trace filter
		trace_t tr;
		UTIL_TraceHull( barrelPos, targetPos, Vector(-asw_weapon_safety_hull.GetFloat(), -asw_weapon_safety_hull.GetFloat(), -asw_weapon_safety_hull.GetFloat()),
						Vector(asw_weapon_safety_hull.GetFloat(), asw_weapon_safety_hull.GetFloat(), asw_weapon_safety_hull.GetFloat()),	MASK_SHOT, &traceFilter, &tr );

		if ( tr.fraction == 1.0 || tr.m_pEnt == npcOwner->GetEnemy() )	
			return true;

		// if a friendly is in the way, then we report failure
		CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( tr.m_pEnt );
		if ( pBCC ) 
		{
			if ( npcOwner->IRelationType( pBCC ) == D_HT )
				return true;

			if ( bSetConditions )
			{
				npcOwner->SetCondition( COND_WEAPON_BLOCKED_BY_FRIEND );
			}
			return false;
		}
	}

	return bHasLOS;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CNPC_Monk::GatherConditions()
{
	BaseClass::GatherConditions();

	// Build my zombie danger index!
	m_iNumZombies = 0;
	m_iDangerousZombies = 0;

	AISightIter_t iter;
	CBaseEntity *pSightEnt;
	pSightEnt = GetSenses()->GetFirstSeenEntity( &iter );
	while( pSightEnt )
	{
		if( pSightEnt->Classify() == CLASS_ZOMBIE && pSightEnt->IsAlive() )
		{
			// Is this zombie coming for me?
			CAI_BaseNPC *pZombie = dynamic_cast<CAI_BaseNPC*>(pSightEnt);
			
			if( pZombie && pZombie->GetEnemy() == this )
			{
				m_iNumZombies++;

				// if this zombie is close enough to attack, add him to the zombie danger!
				float flDist;

				flDist = (pZombie->GetAbsOrigin() - GetAbsOrigin()).Length2DSqr();

				if( flDist <= 128.0f * 128.0f )
				{
					m_iDangerousZombies++;
				}
			}
		}

		pSightEnt = GetSenses()->GetNextSeenEntity( &iter );
	}

	if( m_iDangerousZombies >= 3 || (GetEnemy() && GetHealth() < 25) )
	{
		// I see many zombies, or I'm quite injured.
		SpeakIfAllowed( TLK_HELP_ME );
	}

	// NOTE!!!!!! This code assumes grigori is using annabelle!
	ClearCondition(COND_LOW_PRIMARY_AMMO);
	if ( GetActiveWeapon() )
	{
		if ( GetActiveWeapon()->UsesPrimaryAmmo() )
		{
			if (!GetActiveWeapon()->HasPrimaryAmmo() )
			{
				SetCondition(COND_NO_PRIMARY_AMMO);
			}
			else if ( m_NPCState != NPC_STATE_COMBAT && GetActiveWeapon()->UsesClipsForAmmo1() && GetActiveWeapon()->Clip1() < 2 )
			{
				// Don't send a low ammo message unless we're not in combat.
				SetCondition(COND_LOW_PRIMARY_AMMO);
			}
		}
	}
}
예제 #9
0
//-----------------------------------------------------------------------------
// Purpose: Check the weapon LOS for an owner at an arbitrary position
//			If bSetConditions is true, LOS related conditions will also be set
//-----------------------------------------------------------------------------
bool CBaseCombatWeapon::WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions )
{
	// --------------------
	// Check for occlusion
	// --------------------
	CAI_BaseNPC* npcOwner = m_hOwner.Get()->MyNPCPointer();

	// Find its relative shoot position
	Vector vecRelativeShootPosition;
	VectorSubtract( npcOwner->Weapon_ShootPosition(), npcOwner->GetAbsOrigin(), vecRelativeShootPosition );
	Vector barrelPos = ownerPos + vecRelativeShootPosition;

	// Use the custom LOS trace filter
	CWeaponLOSFilter traceFilter( m_hOwner.Get(), npcOwner->GetEnemy(), COLLISION_GROUP_BREAKABLE_GLASS );
	trace_t tr;
	UTIL_TraceLine( barrelPos, targetPos, MASK_SHOT, &traceFilter, &tr );

	// See if we completed the trace without interruption
	if ( tr.fraction == 1.0 )
	{
		if ( ai_debug_shoot_positions.GetBool() )
		{
			NDebugOverlay::Line( barrelPos, targetPos, 0, 255, 0, false, 1.0 );
		}

		return true;
	}

	CBaseEntity	*pHitEnt = tr.m_pEnt;

	CBasePlayer *pEnemyPlayer = ToBasePlayer( npcOwner->GetEnemy() );

	// is player in a vehicle? if so, verify vehicle is target and return if so (so npc shoots at vehicle)
	if ( pEnemyPlayer && pEnemyPlayer->IsInAVehicle() )
	{
		// Ok, player in vehicle, check if vehicle is target we're looking at, fire if it is
		// Also, check to see if the owner of the entity is the vehicle, in which case it's valid too.
		// This catches vehicles that use bone followers.
		CBaseEntity	*pVehicle  = pEnemyPlayer->GetVehicle()->GetVehicleEnt();
		if ( pHitEnt == pVehicle || pHitEnt->GetOwnerEntity() == pVehicle )
			return true;
	}

	// Hitting our enemy is a success case
	if ( pHitEnt == npcOwner->GetEnemy() )
	{
		if ( ai_debug_shoot_positions.GetBool() )
		{
			NDebugOverlay::Line( barrelPos, targetPos, 0, 255, 0, false, 1.0 );
		}

		return true;
	}

	// If a vehicle is blocking the view, grab its driver and use that as the combat character
	CBaseCombatCharacter *pBCC;
	IServerVehicle *pVehicle = pHitEnt->GetServerVehicle();
	if ( pVehicle )
	{
		pBCC = pVehicle->GetPassenger( );
	}
	else
	{
		pBCC = ToBaseCombatCharacter( pHitEnt );
	}

	if ( pBCC ) 
	{
		if ( npcOwner->IRelationType( pBCC ) == D_HT )
			return true;

		if ( bSetConditions )
		{
			npcOwner->SetCondition( COND_WEAPON_BLOCKED_BY_FRIEND );
		}
	}
	else if ( bSetConditions )
	{
		npcOwner->SetCondition( COND_WEAPON_SIGHT_OCCLUDED );
		npcOwner->SetEnemyOccluder( pHitEnt );

		if( ai_debug_shoot_positions.GetBool() )
		{
			NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 1.0 );
		}
	}

	return false;
}
예제 #10
0
//---------------------------------------------------------
// Purpose: 
//---------------------------------------------------------
void CNPC_Assassin::StartTask( const Task_t *pTask )
{
	switch( pTask->iTask )
	{
	case TASK_ASSASSIN_SET_EYE_STATE:
		{
			SetEyeState( (eyeState_t) ( (int) pTask->flTaskData ) );
			TaskComplete();
		}
		break;

	case TASK_ASSASSIN_EVADE:
		{
			Activity flipAct = ACT_INVALID;

			const Vector *avoidPos = ( GetEnemy() != NULL ) ? &(GetEnemy()->GetAbsOrigin()) : NULL;

			for ( int i = FLIP_LEFT; i < NUM_FLIP_TYPES; i++ )
			{
				if ( CanFlip( i, flipAct, avoidPos ) )
				{
					// Don't flip back to where we just were
					if ( ( ( i == FLIP_LEFT ) && ( m_nLastFlipType == FLIP_RIGHT ) ) ||
						 ( ( i == FLIP_RIGHT ) && ( m_nLastFlipType == FLIP_LEFT ) ) ||
						 ( ( i == FLIP_FORWARD ) && ( m_nLastFlipType == FLIP_BACKWARD ) ) ||
						 ( ( i == FLIP_BACKWARD ) && ( m_nLastFlipType == FLIP_FORWARD ) ) )
					{
						flipAct = ACT_INVALID;
						continue;
					}

					m_nNumFlips--;
					ResetIdealActivity( flipAct );
					m_flNextFlipTime = gpGlobals->curtime + 2.0f;
					m_nLastFlipType = i;
					break;
				}
			}

			if ( flipAct == ACT_INVALID )
			{
				m_nNumFlips = 0;
				m_nLastFlipType = -1;
				m_flNextFlipTime = gpGlobals->curtime + 2.0f;
				TaskFail( "Unable to find flip evasion direction!\n" );
			}
		}
		break;

	case TASK_ASSASSIN_GET_PATH_TO_VANTAGE_POINT:
		{
			assert( GetEnemy() != NULL );
			if ( GetEnemy() == NULL )
				break;

			Vector	goalPos;

			CHintCriteria	hint;

			// Find a disadvantage node near the player, but away from ourselves
			hint.SetHintType( HINT_TACTICAL_ENEMY_DISADVANTAGED );
			hint.AddExcludePosition( GetAbsOrigin(), 256 );
			hint.AddExcludePosition( GetEnemy()->GetAbsOrigin(), 256 );

			if ( ( m_pSquad != NULL ) && ( m_pSquad->NumMembers() > 1 ) )
			{
				AISquadIter_t iter;
				for ( CAI_BaseNPC *pSquadMember = m_pSquad->GetFirstMember( &iter ); pSquadMember; pSquadMember = m_pSquad->GetNextMember( &iter ) )
				{
					if ( pSquadMember == NULL )
						continue;

					hint.AddExcludePosition( pSquadMember->GetAbsOrigin(), 128 );
				}
			}
	
			hint.SetFlag( bits_HINT_NODE_NEAREST );

			CAI_Hint *pHint = CAI_HintManager::FindHint( this, GetEnemy()->GetAbsOrigin(), &hint );

			if ( pHint == NULL )
			{
				TaskFail( "Unable to find vantage point!\n" );
				break;
			}

			pHint->GetPosition( this, &goalPos );

			AI_NavGoal_t goal( goalPos );
			
			//Try to run directly there
			if ( GetNavigator()->SetGoal( goal ) == false )
			{
				TaskFail( "Unable to find path to vantage point!\n" );
				break;
			}
			
			TaskComplete();
		}
		break;

	default:
		BaseClass::StartTask( pTask );
		break;
	}
}
예제 #11
0
//---------------------------------------------------------
//---------------------------------------------------------
void CAI_Relationship::ChangeRelationships( int disposition, int iReverting, CBaseEntity *pActivator, CBaseEntity *pCaller )
{
 	if( iReverting != NOT_REVERTING && m_iPreviousDisposition == -1 )
	{
		// Trying to revert without having ever set the relationships!
		DevMsg( 2, "ai_relationship cannot revert changes before they are applied!\n");
		return;
	}

	const int MAX_HANDLED = 512;
	CUtlVectorFixed<CBaseCombatCharacter *, MAX_HANDLED> subjectList;
	CUtlVectorFixed<CBaseCombatCharacter *, MAX_HANDLED> targetList;

	// Add any special subjects we found
	CBaseEntity *pSpecialSubject = FindEntityForProceduralName( m_iszSubject, pActivator, pCaller );
	if ( pSpecialSubject && pSpecialSubject->MyCombatCharacterPointer() )
	{
		subjectList.AddToTail( pSpecialSubject->MyCombatCharacterPointer() );
	}

	// Add any special targets we found
	CBaseEntity *pSpecialTarget = FindEntityForProceduralName( m_target, pActivator, pCaller );
	if ( pSpecialTarget && pSpecialTarget->MyCombatCharacterPointer() )
	{
		targetList.AddToTail( pSpecialTarget->MyCombatCharacterPointer() );
	}

	// -------------------------------
	// Search for targets and subjects
	// -------------------------------

	float radiusSq = Square( m_flRadius );
	
	// Search players first
	for ( int i = 1; i <= gpGlobals->maxClients; i++ )
	{
		if ( subjectList.Count() == MAX_HANDLED || targetList.Count() == MAX_HANDLED )
		{
			DevMsg( "Too many entities handled by ai_relationship %s\n", GetDebugName() );
			break;
		}

		CBasePlayer	*pPlayer = UTIL_PlayerByIndex( i );
		if ( pPlayer )
		{
			if( IsASubject( pPlayer ) )
			{
				if ( m_flRadius == 0.0 || GetAbsOrigin().DistToSqr( pPlayer->GetAbsOrigin() ) <= radiusSq )
					subjectList.AddToTail( pPlayer );
			}
			else if( IsATarget( pPlayer ) )
			{
				targetList.AddToTail( pPlayer );
			}
		}
	}

	// Search NPCs
	for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ )
	{
		if ( subjectList.Count() == MAX_HANDLED || targetList.Count() == MAX_HANDLED )
		{
			DevMsg( "Too many entities handled by ai_relationship %s\n", GetDebugName() );
			break;
		}

		CAI_BaseNPC *pNPC = (g_AI_Manager.AccessAIs())[i];
		if ( pNPC )
		{
			if( IsASubject( pNPC ) )
			{
				if ( m_flRadius == 0.0 || GetAbsOrigin().DistToSqr( pNPC->GetAbsOrigin() ) <= radiusSq )
					subjectList.AddToTail( pNPC );
			}
			else if( IsATarget( pNPC ) )
			{
				targetList.AddToTail( pNPC );
			}
		}
	}

	// If either list is still empty, we have a problem.
	if( subjectList.Count() == 0 )
	{
		DevMsg( 2, "ai_relationship '%s' finds no subject(s) called: %s\n", GetDebugName(), STRING( m_iszSubject ) );
		return;
	}
	else if ( targetList.Count() == 0 )
	{
		DevMsg( 2, "ai_relationship '%s' finds no target(s) called: %s\n", GetDebugName(), STRING( m_target ) );
		return;
	}

	// Ok, lists are populated. Apply all relationships.
	for ( int i = 0 ; i < subjectList.Count(); i++ )
	{
		CBaseCombatCharacter *pSubject = subjectList[ i ];

		for ( int j = 0 ; j < targetList.Count(); j++ )
		{
			CBaseCombatCharacter *pTarget = targetList[ j ];

			if ( m_iPreviousDisposition == -1 && iReverting == NOT_REVERTING )
			{
				// Set previous disposition.
				m_iPreviousDisposition = pSubject->IRelationType( pTarget );
				m_iPreviousRank = pSubject->IRelationPriority( pTarget );
			}

			if ( iReverting == REVERTING_TO_PREV )
			{
				pSubject->AddEntityRelationship( pTarget, (Disposition_t)m_iPreviousDisposition, m_iPreviousRank );

				if( m_bReciprocal )
				{
					pTarget->AddEntityRelationship( pSubject, (Disposition_t)m_iPreviousDisposition, m_iPreviousRank );
				}
			}
			else if ( iReverting == REVERTING_TO_DEFAULT )
			{
				pSubject->RemoveEntityRelationship( pTarget );

				if( m_bReciprocal )
				{
					pTarget->RemoveEntityRelationship( pSubject );
				}
			}
			else if( pSubject->IRelationType(pTarget) != disposition || 
				     pSubject->IRelationPriority(pTarget) != m_iRank || 
					 HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_SUBJECT ) ||
					 HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_TARGET ) )
			{
				// Apply the relationship to the subject
				pSubject->AddEntityRelationship( pTarget, (Disposition_t)disposition, m_iRank );

				// Make the subject aware of the target
				if ( HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_SUBJECT ) )
				{
					DiscloseNPCLocation( pSubject, pTarget );
				}

				// Make the target aware of the subject
				if ( HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_TARGET ) )
				{
					DiscloseNPCLocation( pTarget, pSubject );
				}

				// This relationship is applied to target and subject alike
				if ( m_bReciprocal )
				{
					// Apply the relationship to the target
					pTarget->AddEntityRelationship( pSubject, (Disposition_t)disposition, m_iRank );
				}
			}
		}
	}
}
예제 #12
0
//---------------------------------------------------------
// Returns distance to the nearest BaseCombatCharacter.
//---------------------------------------------------------
float CBounceBomb::FindNearestNPC()
{
	float flNearest = (BOUNCEBOMB_WARN_RADIUS * BOUNCEBOMB_WARN_RADIUS) + 1.0;

	// Assume this search won't find anyone.
	SetNearestNPC( NULL );

	CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs();
	int nAIs = g_AI_Manager.NumAIs();

	for ( int i = 0; i < nAIs; i++ )
	{
		CAI_BaseNPC *pNPC = ppAIs[ i ];

		if( pNPC->IsAlive() )
		{
			// ignore hidden objects
			if ( pNPC->IsEffectActive( EF_NODRAW ) )
				continue;

			// Don't bother with NPC's that are below me.
			if( pNPC->EyePosition().z < GetAbsOrigin().z )
				continue;

			// Disregard things that want to be disregarded
			if( pNPC->Classify() == CLASS_NONE )
				continue; 

			// Disregard bullseyes
			if( pNPC->Classify() == CLASS_BULLSEYE )
				continue;

			// Disregard turrets
			if( pNPC->m_iClassname == gm_iszFloorTurretClassname || pNPC->m_iClassname == gm_iszGroundTurretClassname )
				continue;


			float flDist = (GetAbsOrigin() - pNPC->GetAbsOrigin()).LengthSqr();

			if( flDist < flNearest )
			{
				// Now do a visibility test.
				if( FVisible( pNPC, MASK_SOLID_BRUSHONLY ) )
				{
					flNearest = flDist;
					SetNearestNPC( pNPC );
				}
			}
		}
	}

	// finally, check the player.
	CBasePlayer *pPlayer = UTIL_GetLocalPlayer();

	if( pPlayer && !(pPlayer->GetFlags() & FL_NOTARGET) )
	{
		float flDist = (pPlayer->GetAbsOrigin() - GetAbsOrigin() ).LengthSqr();

		if( flDist < flNearest && FVisible( pPlayer, MASK_SOLID_BRUSHONLY ) )
		{
			flNearest = flDist;
			SetNearestNPC( pPlayer );
		}
	}

	if( m_hNearestNPC.Get() )
	{
		// If sprite is active, update its color to reflect who is nearest.
		if( IsFriend( m_hNearestNPC ) )
		{
			if( m_bFoeNearest )
			{
				// Changing state to where a friend is nearest.

				if( IsFriend( m_hNearestNPC ) )
				{
					// Friend
					UpdateLight( true, 0, 255, 0, 190 );
					m_bFoeNearest = false;
				}
			}
		}
		else // it's a foe
		{
			if( !m_bFoeNearest )
			{
				// Changing state to where a foe is nearest.
				UpdateLight( true, 255, 0, 0, 190 );
				m_bFoeNearest = true;
			}
		}
	}

	return sqrt( flNearest );
}
예제 #13
0
//-----------------------------------------------------------------------------
// Look for a target
//-----------------------------------------------------------------------------
bool CObjectSentrygun::FindTarget()
{
	// Disable the sentry guns for ifm.
	if ( tf_sentrygun_notarget.GetBool() )
		return false;

	if ( IsInCommentaryMode() )
		return false;

	// Sapper, etc.
	if ( IsDisabled() )
		return false;

	// Loop through players within 1100 units (sentry range).
	Vector vecSentryOrigin = EyePosition();

	// Find the opposing team list.
	CTFPlayer *pPlayer = ToTFPlayer( GetOwner() );
	CUtlVector<CTFTeam *> pTeamList;
	CTFTeam *pTeam = NULL;

	//CTFTeam *pTeam = pPlayer->GetOpposingTFTeam();
	//if ( !pTeam )
	//	return false;

	if ( pPlayer )
	{
		// Try builder's team.
		pTeam = pPlayer->GetTFTeam();
	}
	else
	{
		// If we have no builder use our own team number instead.
		pTeam = GetTFTeam();
	}

	if ( pTeam )
		pTeam->GetOpposingTFTeamList( &pTeamList );
	else
		return false;

	// If we have an enemy get his minimum distance to check against.
	Vector vecSegment;
	Vector vecTargetCenter;
	float flMinDist2 = 1100.0f * 1100.0f;
	CBaseEntity *pTargetCurrent = NULL;
	CBaseEntity *pTargetOld = m_hEnemy.Get();
	float flOldTargetDist2 = FLT_MAX;

	// Sentries will try to target players first, then objects.  However, if the enemy held was an object it will continue
	// to try and attack it first.

	for (int i = 0; i < pTeamList.Size(); i++)
	{
		int nTeamCount = pTeamList[i]->GetNumPlayers();
		for (int iPlayer = 0; iPlayer < nTeamCount; ++iPlayer)
		{
			CTFPlayer *pTargetPlayer = static_cast<CTFPlayer*>(pTeamList[i]->GetPlayer(iPlayer));
			if (pTargetPlayer == NULL)
				continue;

			// Make sure the player is alive.
			if (!pTargetPlayer->IsAlive())
				continue;

			if (pTargetPlayer->GetFlags() & FL_NOTARGET)
				continue;

			vecTargetCenter = pTargetPlayer->GetAbsOrigin();
			vecTargetCenter += pTargetPlayer->GetViewOffset();
			VectorSubtract(vecTargetCenter, vecSentryOrigin, vecSegment);
			float flDist2 = vecSegment.LengthSqr();

			// Store the current target distance if we come across it
			if (pTargetPlayer == pTargetOld)
			{
				flOldTargetDist2 = flDist2;
			}

			// Check to see if the target is closer than the already validated target.
			if (flDist2 > flMinDist2)
				continue;

			// It is closer, check to see if the target is valid.
			if (ValidTargetPlayer(pTargetPlayer, vecSentryOrigin, vecTargetCenter))
			{
				flMinDist2 = flDist2;
				pTargetCurrent = pTargetPlayer;
			}
		}

		// If we already have a target, don't check objects.
		if (pTargetCurrent == NULL)
		{
			int nTeamObjectCount = pTeamList[i]->GetNumObjects();
			for (int iObject = 0; iObject < nTeamObjectCount; ++iObject)
			{
				CBaseObject *pTargetObject = pTeamList[i]->GetObject(iObject);
				if (!pTargetObject)
					continue;

				vecTargetCenter = pTargetObject->GetAbsOrigin();
				vecTargetCenter += pTargetObject->GetViewOffset();
				VectorSubtract(vecTargetCenter, vecSentryOrigin, vecSegment);
				float flDist2 = vecSegment.LengthSqr();

				// Store the current target distance if we come across it
				if (pTargetObject == pTargetOld)
				{
					flOldTargetDist2 = flDist2;
				}

				// Check to see if the target is closer than the already validated target.
				if (flDist2 > flMinDist2)
					continue;

				// It is closer, check to see if the target is valid.
				if (ValidTargetObject(pTargetObject, vecSentryOrigin, vecTargetCenter))
				{
					flMinDist2 = flDist2;
					pTargetCurrent = pTargetObject;
				}
			}
		}

		// NPCs have lowest priority.
		if (pTargetCurrent == NULL)
		{
			int nTeamNPCCount = pTeamList[i]->GetNumNPCs();
			for (int iNPC = 0; iNPC < nTeamNPCCount; ++iNPC)
			{
				CAI_BaseNPC *pTargetNPC = pTeamList[i]->GetNPC(iNPC);
				if (!pTargetNPC)
					continue;

				// Make sure NPC is alive.
				if (!pTargetNPC->IsAlive())
					continue;

				vecTargetCenter = pTargetNPC->GetAbsOrigin();
				vecTargetCenter += pTargetNPC->GetViewOffset();
				//vecTargetCenter = pTargetNPC->WorldSpaceCenter();
				VectorSubtract(vecTargetCenter, vecSentryOrigin, vecSegment);
				float flDist2 = vecSegment.LengthSqr();

				// Store the current target distance if we come across it
				if (pTargetNPC == pTargetOld)
				{
					flOldTargetDist2 = flDist2;
				}

				// Check to see if the target is closer than the already validated target.
				if (flDist2 > flMinDist2)
					continue;

				// It is closer, check to see if the target is valid.
				if (ValidTargetNPC(pTargetNPC, vecSentryOrigin, vecTargetCenter))
				{
					flMinDist2 = flDist2;
					pTargetCurrent = pTargetNPC;
				}
			}
		}

		// We have a target.
		if (pTargetCurrent)
		{
			if (pTargetCurrent != pTargetOld)
			{
				// flMinDist2 is the new target's distance
				// flOldTargetDist2 is the old target's distance
				// Don't switch unless the new target is closer by some percentage
				if (flMinDist2 < (flOldTargetDist2 * 0.75f))
				{
					FoundTarget(pTargetCurrent, vecSentryOrigin);
				}
			}
			return true;
		}
	}

	return false;
}
//=========================================================
// Crea un hijo en la ubicación especificada.
//=========================================================
bool CDirector_Manager::AddChild(const Vector &vecPosition, int flag)
{
	// No se ha podido acceder al Director.
	if ( !Director() )
		return false;

	// No es posible crear un hijo aquí.
	if ( !CanMake(vecPosition) )
		return false;

	// Creamos un hijo de la lista.
	const char *pChildName	= GetChildClass();
	CAI_BaseNPC *pChild		= (CAI_BaseNPC *)CreateEntityByName(pChildName);

	QAngle angles = RandomAngle(0, 360);
	angles.x = 0.0;
	angles.z = 0.0;	
	pChild->SetAbsAngles(angles);

	// Establecemos la ubicación de creación.
	pChild->SetAbsOrigin(vecPosition);

	// Debe caer al suelo y desaparecer.
	pChild->AddSpawnFlags(SF_NPC_FALL_TO_GROUND);
	pChild->AddSpawnFlags(SF_NPC_FADE_CORPSE);

	UTIL_DropToFloor(pChild, MASK_SOLID);

	ConVarRef director_debug("director_debug");

	DispatchSpawn(pChild);
	pChild->SetOwnerEntity(Director());
	DispatchActivate(pChild);

	// ¡¡NO CAMBIAR!!
	pChild->SetName(MAKE_STRING(CHILD_NAME));

	// Sin colisiones.
	if ( flag == SPAWN_NO_COLLISION || flag == SPAWN_NO_COLLISION_AND_POWERFUL )
	{
		pChild->SetCollisionGroup(COLLISION_GROUP_SPECIAL_NPC);
		Vector vecOriginRadius;

		if ( Director()->Status == PANIC && RandomInt(0, 4) == 2 )
			pChild->SetCollisionGroup(COLLISION_GROUP_NPC);

		// Intentamos crearlo en un radio de 100
		if ( CAI_BaseNPC::FindSpotForNPCInRadius(&vecOriginRadius, vecPosition, pChild, 150, false) )
		{
			// Evitamos que se mueva por debajo del suelo.
			vecOriginRadius.z = vecPosition.z;

			// Movemos hacia esta ubicación.
			pChild->SetAbsOrigin(vecOriginRadius);

			// Marcamos al nodo afortunado. (Naranja)
			if ( director_debug.GetBool() )
				NDebugOverlay::Box(vecOriginRadius, -Vector(10, 10, 10), Vector(10, 10, 10), 255, 128, 0, 10, 20.0f);
		}
	}

	// Poderoso.
	if ( flag == SPAWN_POWERFUL || flag == SPAWN_NO_COLLISION_AND_POWERFUL )
	{
		int moreHealth = 3;

		// Normal: 5 más de salud.
		if ( InGameRules()->IsSkillLevel(SKILL_MEDIUM) ) 
			moreHealth = 5;

		// Dificil: 8 más de salud.
		if ( InGameRules()->IsSkillLevel(SKILL_HARD) )
			moreHealth = 8;

		// Más rápido.
		pChild->SetAddAccel(40);

		// Establecemos la nueva salud.
		pChild->SetMaxHealth(pChild->GetMaxHealth() + moreHealth);
		pChild->SetHealth(pChild->GetMaxHealth());

		// Seleccionamos al jugador más cercano.
		float flDistance = 0.0f;
		CIN_Player *pPlayer = UTIL_GetNearestInPlayer(pChild->GetAbsOrigin(), flDistance);

		if ( pPlayer )
		{
			// Le decimos que su nuevo enemigo es el jugador y le damos la ubicación de este.
			pChild->SetEnemy(pPlayer);
			pChild->UpdateEnemyMemory(pPlayer, pPlayer->GetAbsOrigin());
		}
	}

	// Al parecer se atoro en una pared.
	if ( !PostSpawn(pChild) )
	{
		// Marcamos al nodo desafortunado. (Negro)
		if ( director_debug.GetBool() )
			NDebugOverlay::Box(vecPosition, -Vector(10, 10, 10), Vector(10, 10, 10), 0, 0, 0, 10, 3.0f);

		return false;
	}

	// Marcamos al nodo afortunado. (Rojo)
	if ( director_debug.GetBool() )
		NDebugOverlay::Box(vecPosition, -Vector(10, 10, 10), Vector(10, 10, 10), 223, 1, 1, 10, 3.0f);

	DevMsg("[MANAGER] Se ha creado <%s> (faltan %i) \r\n", pChildName, Director()->SpawnQueue);
	++Director()->ChildsSpawned;

	return true;
}