Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

488 lines
12 KiB

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "beam_shared.h"
#include "ai_motor.h"
#include "asw_ai_behavior_flick.h"
#include "ai_hint.h"
#include "ai_navigator.h"
#include "ai_memory.h"
#include "asw_alien.h"
#include "movevars_shared.h"
#include "asw_marine.h"
#include "asw_player.h"
#include "asw_director.h"
#include "asw_gamerules.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
BEGIN_DATADESC( CAI_ASW_FlickBehavior )
END_DATADESC();
LINK_BEHAVIOR_TO_CLASSNAME( CAI_ASW_FlickBehavior );
//#define DRAW_DEBUG 1
typedef struct SFlickInfo
{
Activity m_Activity;
float m_flMinDot;
float m_flMaxDot;
} TFlickInfo;
#define MAX_FLICKS 4
static TFlickInfo FlickInfo[ MAX_FLICKS ] =
{
{ ACT_FLICK_LEFT, 0.45f, 0.8f },
{ ACT_FLICK_LEFT_MIDDLE, 0.0f, 0.45f },
{ ACT_FLICK_RIGHT_MIDDLE, -0.45f, 0.0f },
{ ACT_FLICK_RIGHT, -0.8f, -0.45f }
};
//------------------------------------------------------------------------------
// Purpose: constructor
//------------------------------------------------------------------------------
CAI_ASW_FlickBehavior::CAI_ASW_FlickBehavior( )
{
m_flDistance = -1;
m_flDistanceSq = -1;
m_flMinDamage = 1.0f;
m_flMaxDamage = 1.0f;
m_pPickedFlick = NULL;
m_flNextFlickCheck = 0.0f;
}
//------------------------------------------------------------------------------
// Purpose: function to set up parameters
// Input : szKeyName - the name of the key
// szValue - the value to be set
// Output : returns true of we handled this key
//------------------------------------------------------------------------------
bool CAI_ASW_FlickBehavior::KeyValue( const char *szKeyName, const char *szValue )
{
if ( V_stricmp( szKeyName, "distance" ) == 0 )
{
m_flDistance = atof( szValue );
m_flDistanceSq = m_flDistance * m_flDistance;
return true;
}
else if ( V_stricmp( szKeyName, "propel_distance" ) == 0 )
{
m_flPropelDistance = atof( szValue );
return true;
}
else if ( V_stricmp( szKeyName, "propel_height" ) == 0 )
{
m_flPropelHeight = atof( szValue );
return true;
}
else if ( V_stricmp( szKeyName, "min_damage" ) == 0 )
{
m_flMinDamage = atof( szValue );
return true;
}
else if ( V_stricmp( szKeyName, "max_damage" ) == 0 )
{
m_flMaxDamage = atof( szValue );
return true;
}
return BaseClass::KeyValue( szKeyName, szValue );
}
//------------------------------------------------------------------------------
// Purpose: precaches any additional assets this behavior needs
//------------------------------------------------------------------------------
void CAI_ASW_FlickBehavior::Precache( void )
{
BaseClass::Precache();
}
//------------------------------------------------------------------------------
// Purpose:
//------------------------------------------------------------------------------
void CAI_ASW_FlickBehavior::Init( )
{
}
//------------------------------------------------------------------------------
// Purpose: determines if we can use this behavior currently
// Output : returns true if this behavior is able to run
//------------------------------------------------------------------------------
bool CAI_ASW_FlickBehavior::CanSelectSchedule()
{
if ( !GetOuter()->IsInterruptable() )
{
return false;
}
if ( HasCondition( COND_SHIELD_CAN_FLICK ) == false )
{
return false;
}
return BaseClass::CanSelectSchedule();
}
//------------------------------------------------------------------------------
// Purpose: sets / clears conditions for when the behavior is active. this is
// generally a larger set of conditions to interrupt any tasks.
//------------------------------------------------------------------------------
void CAI_ASW_FlickBehavior::GatherConditions( )
{
BaseClass::GatherConditions();
}
//------------------------------------------------------------------------------
// Purpose: sets / clears conditions for when the behavior is not active. this is
// mainly to have a smaller set of conditions to wake up the behavior.
//------------------------------------------------------------------------------
void CAI_ASW_FlickBehavior::GatherConditionsNotActive( )
{
BaseClass::GatherConditionsNotActive();
if ( m_flNextFlickCheck < gpGlobals->curtime )
{
if ( GetFlickActivity() != NULL )
{
SetCondition( COND_SHIELD_CAN_FLICK );
}
m_flNextFlickCheck = gpGlobals->curtime + 1.0f;
}
}
void CAI_ASW_FlickBehavior::BeginScheduleSelection( )
{
m_pPickedFlick = NULL;
}
void CAI_ASW_FlickBehavior::EndScheduleSelection( )
{
}
//------------------------------------------------------------------------------
// Purpose: general purpose routine to collect conditions used both during active
// and non-active states of the behavior.
//------------------------------------------------------------------------------
void CAI_ASW_FlickBehavior::GatherCommonConditions( )
{
BaseClass::GatherCommonConditions();
}
//------------------------------------------------------------------------------
// Purpose: routine called to start when a task initially starts
// Input : pTask - the task structure
//------------------------------------------------------------------------------
void CAI_ASW_FlickBehavior::StartTask( const Task_t *pTask )
{
switch( pTask->iTask )
{
case TASK_SHIELD_FLICK:
{
ClearCondition( COND_SHIELD_CAN_FLICK );
m_pPickedFlick = GetFlickActivity();
if ( m_pPickedFlick != NULL )
{
GetOuter()->RestartGesture( m_pPickedFlick->m_Activity );
}
}
break;
default:
BaseClass::StartTask( pTask );
break;
}
}
//------------------------------------------------------------------------------
// Purpose: routine called every frame when a task is running
// Input : pTask - the task structure
//------------------------------------------------------------------------------
void CAI_ASW_FlickBehavior::RunTask( const Task_t *pTask )
{
switch( pTask->iTask )
{
case TASK_SHIELD_FLICK:
if ( !m_pPickedFlick || GetOuter()->IsPlayingGesture( m_pPickedFlick->m_Activity ) == false )
{
TaskComplete();
m_pPickedFlick = NULL;
}
break;
default:
BaseClass::RunTask( pTask );
break;
}
}
//------------------------------------------------------------------------------
// Purpose: routine called to select what schedule we want to run
// Output : returns the schedule id of the schedule we want to run
//------------------------------------------------------------------------------
int CAI_ASW_FlickBehavior::SelectSchedule()
{
return SCHED_SHIELD_FLICK;
}
TFlickInfo *CAI_ASW_FlickBehavior::GetFlickActivity( )
{
Vector vRightNPC, vForwardNPC, vForwardEnemy;
int nCount = 0;
int nFlickTotal[ MAX_FLICKS ];
for( int i = 0; i < MAX_FLICKS; i++ )
{
nFlickTotal[ i ] = 0;
}
AngleVectors( GetAbsAngles(), &vForwardNPC, &vRightNPC, NULL );
#ifdef DRAW_DEBUG
UTIL_AddDebugLine( GetAbsOrigin(), GetAbsOrigin() + vForwardNPC * 300.0f, true, false );
#endif // #ifdef DRAW_DEBUG
AIEnemiesIter_t iter;
for( AI_EnemyInfo_t *pEMemory = GetEnemies()->GetFirst( &iter ); pEMemory != NULL; pEMemory = GetEnemies()->GetNext( &iter ) )
{
CBaseEntity *pEntity = pEMemory->hEnemy;
Vector vDelta = GetAbsOrigin() - pEntity->GetAbsOrigin();
float flLenSq = vDelta.LengthSqr();
if ( flLenSq > m_flDistanceSq )
{
continue;
}
#ifdef DRAW_DEBUG
UTIL_AddDebugLine( GetAbsOrigin(), pEntity->GetAbsOrigin(), true, false );
#endif // #ifdef DRAW_DEBUG
vForwardEnemy = vDelta;
vForwardEnemy.NormalizeInPlace();
float flResult = vForwardNPC.Dot( vForwardEnemy );
if ( flResult > 0.0f )
{ // we are behind
continue;
}
flResult = vRightNPC.Dot( vForwardEnemy );
for( int j = 0; j < MAX_FLICKS; j++ )
{
if ( flResult >= FlickInfo[ j ].m_flMinDot && flResult <= FlickInfo[ j ].m_flMaxDot )
{ // we are within the flick angle of this arm
nFlickTotal[ j ]++;
nCount++;
break;
}
}
}
if ( nCount > 0 )
{
int nTotal = 0;
nCount = RandomInt( 0, nCount - 1 );
for( int j = 0; j < MAX_FLICKS; j++ )
{
nTotal += nFlickTotal[ j ];
if ( nCount < nTotal )
{
return &FlickInfo[ j ];
}
}
}
return NULL;
}
//------------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//------------------------------------------------------------------------------
void CAI_ASW_FlickBehavior::TryFlicking( CBaseEntity *pEntity )
{
Vector vRightNPC, vForwardNPC, vForwardEnemy;
Vector vDelta = GetAbsOrigin() - pEntity->GetAbsOrigin();
float flLenSq = vDelta.LengthSqr();
if ( flLenSq > m_flDistanceSq )
{
return;
}
vForwardEnemy = vDelta;
vForwardEnemy.NormalizeInPlace();
AngleVectors( GetAbsAngles(), &vForwardNPC, &vRightNPC, NULL );
float flResult = vForwardNPC.Dot( vForwardEnemy );
if ( flResult > 0.0f )
{ // we are behind
return;
}
flResult = vRightNPC.Dot( vForwardEnemy );
if ( flResult < m_pPickedFlick->m_flMinDot || flResult > m_pPickedFlick->m_flMaxDot )
{ // we are not within the flick angle of the flicking arm
return;
}
CASW_Alien *pOwner = dynamic_cast< CASW_Alien * >( GetOuter() );
float flMinDamage = ASWGameRules()->ModifyAlienDamageBySkillLevel( m_flMinDamage );
float flMaxDamage = ASWGameRules()->ModifyAlienDamageBySkillLevel( m_flMaxDamage );
flMinDamage = ( flMinDamage < 1.0f ? 1.0f : flMinDamage );
flMaxDamage = ( flMaxDamage < 1.0f ? 1.0f : flMaxDamage );
CTakeDamageInfo info( pOwner, pOwner, RandomFloat( flMinDamage, flMaxDamage ), DMG_GENERIC );
Vector killDir = pEntity->GetAbsOrigin() - GetAbsOrigin();
VectorNormalize( killDir );
info.SetDamageForce( killDir );
info.SetDamagePosition( GetAbsOrigin() );
float flTime = sqrt( ( 2.0f * m_flPropelHeight / sv_gravity.GetFloat() ) );
vDelta = -vDelta;
vDelta.z = 0.0f;
vDelta.NormalizeInPlace();
vDelta *= m_flPropelDistance / ( flTime * 2.0f );
vDelta.z = sv_gravity.GetFloat() * flTime;
CASW_Player *pPlayer = dynamic_cast< CASW_Player * >( pEntity );
if ( pPlayer )
{
CASW_Marine *pBaseMarine = pPlayer->GetMarine();
// CASW_Marine *pBaseMarine = CASW_Marine::AsMarine( pEntity );
if ( pBaseMarine )
{
pBaseMarine->TakeDamage( info );
pBaseMarine->m_bNoAirControl = true;
pBaseMarine->SetAbsVelocity( vDelta );
pBaseMarine->SetGroundEntity( NULL );
return;
}
}
else
{
pEntity->TakeDamage( info );
}
pEntity->SetAbsVelocity( vDelta );
pEntity->SetGroundEntity( NULL );
}
//------------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//------------------------------------------------------------------------------
void CAI_ASW_FlickBehavior::Flick( )
{
#if 0
for( int i = 0; i < ASWDirector()->GetNPCListCount(); i++ )
{
CASW_Alien *pAlien = ASWDirector()->GetNPCFromList( i );
if ( !pAlien || !pAlien->IsAlive() )
{
continue;
}
if ( GetOuter() != pAlien )
{
TryFlicking( pAlien );
}
}
for ( int i = 0; i < ASW_MAX_READY_PLAYERS; i++ )
{
// found a connected player?
CASW_Player *pOtherPlayer = dynamic_cast< CASW_Player * >( UTIL_PlayerByIndex( i + 1 ) );
// if they're not connected, skip them
if ( !pOtherPlayer || !pOtherPlayer->IsConnected() )
{
continue;
}
TryFlicking( pOtherPlayer );
}
#else
AIEnemiesIter_t iter;
for( AI_EnemyInfo_t *pEMemory = GetEnemies()->GetFirst( &iter ); pEMemory != NULL; pEMemory = GetEnemies()->GetNext( &iter ) )
{
CBaseEntity *pEntity = pEMemory->hEnemy;
if ( pEntity->IsAlive() && GetOuter() != pEntity )
{
TryFlicking( pEntity );
}
}
#endif
// turn this into an area of affect
// reverse his velocity - if he is coming towards the shield bug, add that back into his outgoing to increase it
}
//------------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//------------------------------------------------------------------------------
void CAI_ASW_FlickBehavior::HandleBehaviorEvent( CBaseEntity *pInflictor, BehaviorEvent_t eEvent, int nParm )
{
switch( eEvent )
{
case BEHAVIOR_EVENT_FLICK:
Flick();
break;
}
}
AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( CAI_ASW_FlickBehavior )
DECLARE_TASK( TASK_SHIELD_FLICK )
DECLARE_CONDITION( COND_SHIELD_CAN_FLICK )
DEFINE_SCHEDULE
(
SCHED_SHIELD_FLICK,
" Tasks"
" TASK_SHIELD_FLICK 0"
""
" Interrupts"
" "
);
AI_END_CUSTOM_SCHEDULE_PROVIDER()
#include "tier0/memdbgoff.h"