mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-31 22:49:19 +00:00
upload "kind" alien swarm
This commit is contained in:
@@ -0,0 +1,527 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "beam_shared.h"
|
||||
#include "ai_motor.h"
|
||||
#include "asw_ai_behavior_mortar.h"
|
||||
#include "ai_hint.h"
|
||||
#include "ai_navigator.h"
|
||||
#include "ai_memory.h"
|
||||
#include "asw_alien.h"
|
||||
#include "asw_player.h"
|
||||
#include "particle_parse.h"
|
||||
#include "particles/particles.h"
|
||||
#include "asw_mortar_round.h"
|
||||
#include "movevars_shared.h"
|
||||
#include "te_effect_dispatch.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
BEGIN_DATADESC( CAI_ASW_MortarBehavior )
|
||||
END_DATADESC();
|
||||
|
||||
LINK_BEHAVIOR_TO_CLASSNAME( CAI_ASW_MortarBehavior );
|
||||
|
||||
|
||||
extern ConVar asw_mortar_round_gravity;
|
||||
|
||||
|
||||
//#define DRAW_DEBUG 1
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose: constructor
|
||||
//------------------------------------------------------------------------------
|
||||
CAI_ASW_MortarBehavior::CAI_ASW_MortarBehavior( )
|
||||
{
|
||||
m_flMinFiringDistance = 200.0f;
|
||||
m_flMaxFiringDistance = 800.0f;
|
||||
m_flMaxFiringDistanceSq = m_flMaxFiringDistance * m_flMaxFiringDistance;;
|
||||
|
||||
m_flDamageRadius = 100.0f;
|
||||
m_flDamageRadiusSq = m_flDamageRadius * m_flDamageRadius;
|
||||
|
||||
m_flAccuracy = 150.0f;
|
||||
|
||||
m_flProjectileVelocity = 300.0f;
|
||||
|
||||
m_flDamageAmount = 10.0f;
|
||||
|
||||
m_flFireRate = 2.0;
|
||||
|
||||
m_flBlockedAmount = -1.0f;
|
||||
m_flDeferUntil = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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_MortarBehavior::KeyValue( const char *szKeyName, const char *szValue )
|
||||
{
|
||||
if ( V_stricmp( szKeyName, "minRange" ) == 0 )
|
||||
{
|
||||
m_flMinFiringDistance = atof( szValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( V_stricmp( szKeyName, "maxRange" ) == 0 )
|
||||
{
|
||||
m_flMaxFiringDistance = atof( szValue );
|
||||
m_flMaxFiringDistanceSq = m_flMaxFiringDistance * m_flMaxFiringDistance;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( V_stricmp( szKeyName, "radius" ) == 0 )
|
||||
{
|
||||
m_flDamageRadius = atof( szValue );
|
||||
m_flDamageRadiusSq = m_flDamageRadius * m_flDamageRadius;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( V_stricmp( szKeyName, "velocity" ) == 0 )
|
||||
{
|
||||
m_flProjectileVelocity = atof( szValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( V_stricmp( szKeyName, "damage" ) == 0 )
|
||||
{
|
||||
m_flDamageAmount = atof( szValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( V_stricmp( szKeyName, "rate" ) == 0 )
|
||||
{
|
||||
m_flFireRate = atof( szValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( V_stricmp( szKeyName, "accuracy" ) == 0 )
|
||||
{
|
||||
m_flAccuracy = atof( szValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
return BaseClass::KeyValue( szKeyName, szValue );
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose: precaches any additional assets this behavior needs
|
||||
//------------------------------------------------------------------------------
|
||||
void CAI_ASW_MortarBehavior::Precache( void )
|
||||
{
|
||||
BaseClass::Precache();
|
||||
|
||||
PrecacheParticleSystem( "impact_mortar_preattack" );
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//------------------------------------------------------------------------------
|
||||
void CAI_ASW_MortarBehavior::Init()
|
||||
{
|
||||
CASW_Alien *pNPC = static_cast<CASW_Alien*>( GetOuter() );
|
||||
if ( !pNPC )
|
||||
return;
|
||||
|
||||
pNPC->rangeAttack1.Init( m_flMinFiringDistance, m_flMaxFiringDistance, COMBAT_COND_NO_FACING_CHECK, true );
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose: determines if we can use this behavior currently
|
||||
// Output : returns true if this behavior is able to run
|
||||
//------------------------------------------------------------------------------
|
||||
bool CAI_ASW_MortarBehavior::CanSelectSchedule()
|
||||
{
|
||||
if ( !GetOuter()->IsInterruptable() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !HasCondition( COND_CAN_RANGE_ATTACK1 ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( m_flDeferUntil > gpGlobals->curtime )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return BaseClass::CanSelectSchedule();
|
||||
}
|
||||
|
||||
|
||||
void CAI_ASW_MortarBehavior::HandleBehaviorEvent( CBaseEntity *pInflictor, BehaviorEvent_t eEvent, int nParm )
|
||||
{
|
||||
switch( eEvent )
|
||||
{
|
||||
case BEHAVIOR_EVENT_MORTAR_FIRE:
|
||||
LaunchMortar();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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_MortarBehavior::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_MortarBehavior::GatherConditionsNotActive( )
|
||||
{
|
||||
BaseClass::GatherConditionsNotActive();
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose: general purpose routine to collect conditions used both during active
|
||||
// and non-active states of the behavior.
|
||||
//------------------------------------------------------------------------------
|
||||
void CAI_ASW_MortarBehavior::GatherCommonConditions( )
|
||||
{
|
||||
BaseClass::GatherCommonConditions();
|
||||
}
|
||||
|
||||
|
||||
void CAI_ASW_MortarBehavior::BadLocation( )
|
||||
{
|
||||
m_flDeferUntil = gpGlobals->curtime + 1.0f;
|
||||
GetOuter()->ClearSchedule( "No target location" );
|
||||
}
|
||||
|
||||
|
||||
void CAI_ASW_MortarBehavior::FindMortarLocation( )
|
||||
{
|
||||
int nTotalPotential = GetEnemies()->NumEnemies();
|
||||
|
||||
CBaseEntity **pEligibleEnemies = ( CBaseEntity ** )stackalloc( sizeof( CBaseEntity * ) * nTotalPotential );
|
||||
Vector *vNearPlayerCenter = ( Vector * )stackalloc( sizeof( Vector ) * nTotalPotential );
|
||||
int *nNearPlayerThreat = ( int * )stackalloc( sizeof( int ) * nTotalPotential );
|
||||
int *nNearPlayerCount = ( int * )stackalloc( sizeof( int ) * nTotalPotential );
|
||||
int nEligibleCount = 0;
|
||||
|
||||
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_flMaxFiringDistanceSq )
|
||||
{
|
||||
pEligibleEnemies[ nEligibleCount ] = pEntity;
|
||||
vNearPlayerCenter[ nEligibleCount ] = pEntity->GetAbsOrigin();
|
||||
nNearPlayerThreat[ nEligibleCount ] = GetOuter()->IRelationPriority( pEntity );
|
||||
nNearPlayerCount[ nEligibleCount ] = 1;
|
||||
|
||||
nEligibleCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( nEligibleCount == 0 )
|
||||
{
|
||||
m_flBlockedAmount = 0.0f;
|
||||
BadLocation();
|
||||
return;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < nEligibleCount; i++ )
|
||||
{
|
||||
for ( int j = 0; j < nEligibleCount; j++ )
|
||||
{
|
||||
if ( i == j )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector vDelta = pEligibleEnemies[ i ]->GetAbsOrigin() - pEligibleEnemies[ j ]->GetAbsOrigin();
|
||||
|
||||
float flLenSq = vDelta.LengthSqr();
|
||||
if ( flLenSq <= m_flDamageRadiusSq * 2.0f )
|
||||
{
|
||||
vNearPlayerCenter[ i ] += pEligibleEnemies[ j ]->GetAbsOrigin();
|
||||
nNearPlayerThreat[ i ] += GetOuter()->IRelationPriority( pEligibleEnemies[ j ] );
|
||||
nNearPlayerCount[ i ]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nBestLocation = 0;
|
||||
int nBestThreat = -999;
|
||||
for ( int i = 0; i < nEligibleCount; i++ )
|
||||
{
|
||||
if ( nNearPlayerThreat[ i ] > nBestThreat )
|
||||
{
|
||||
nBestLocation = i;
|
||||
nBestThreat = nNearPlayerThreat[ i ];
|
||||
}
|
||||
}
|
||||
|
||||
vNearPlayerCenter[ nBestLocation ] /= nNearPlayerCount[ nBestLocation ];
|
||||
m_vMortarLocation = vNearPlayerCenter[ nBestLocation ];
|
||||
m_vMortarLocation.x += RandomFloat( -m_flAccuracy, m_flAccuracy );
|
||||
m_vMortarLocation.y += RandomFloat( -m_flAccuracy, m_flAccuracy );
|
||||
}
|
||||
|
||||
|
||||
void CAI_ASW_MortarBehavior::CalcVelocity( Vector &vVelocity )
|
||||
{
|
||||
vVelocity = ( m_vMortarLocation - GetAbsOrigin() );
|
||||
float flLength = vVelocity.NormalizeInPlace();
|
||||
vVelocity *= m_flProjectileVelocity;
|
||||
|
||||
float flGravity = sv_gravity.GetFloat() * asw_mortar_round_gravity.GetFloat();
|
||||
float flTime = flLength / m_flProjectileVelocity;
|
||||
flTime /= 2.0f;
|
||||
float flVelocity = flGravity * flTime;
|
||||
vVelocity.z = flVelocity;
|
||||
}
|
||||
|
||||
|
||||
void CAI_ASW_MortarBehavior::ValidateMortarLocation( )
|
||||
{
|
||||
trace_t tr;
|
||||
Vector vStart = GetAbsOrigin() + Vector( 0.0f, 0.0f, 15.0f );
|
||||
|
||||
m_flBlockedAmount = -1.0f;
|
||||
|
||||
#ifdef DRAW_DEBUG
|
||||
UTIL_AddDebugLine( vStart, m_vMortarLocation + Vector( 0.0f, 0.0f, 15.0f ), true, true );
|
||||
#endif // #ifdef DRAW_DEBUG
|
||||
UTIL_TraceLine( vStart, m_vMortarLocation + Vector( 0.0f, 0.0f, 15.0f ), MASK_SOLID, GetOuter(), ASW_COLLISION_GROUP_IGNORE_NPCS, &tr );
|
||||
if ( tr.fraction >= 0.90f )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const int nSubdivisions = 5;
|
||||
|
||||
Vector vVelocity;
|
||||
CalcVelocity( vVelocity );
|
||||
|
||||
float flGravity = sv_gravity.GetFloat() * asw_mortar_round_gravity.GetFloat();
|
||||
Vector vAcceleration( 0.0f, 0.0f, -flGravity );
|
||||
float flTotalTime = ( m_vMortarLocation - GetAbsOrigin() ).Length() / m_flProjectileVelocity;
|
||||
|
||||
float flTime = 0.0f;
|
||||
float flTimeStep = ( flTotalTime / ( ( float ) ( nSubdivisions - 1 ) ) );
|
||||
Vector vLast;
|
||||
|
||||
m_flBlockedAmount = 0.0f;
|
||||
|
||||
for( int i = 0; i < nSubdivisions; i++ )
|
||||
{
|
||||
Vector vFinal = vStart + ( vVelocity * flTime ) + ( 0.5f * flTime * flTime * vAcceleration );
|
||||
flTime += flTimeStep;
|
||||
|
||||
if ( i > 0 )
|
||||
{
|
||||
m_flBlockedAmount += flTimeStep;
|
||||
|
||||
#ifdef DRAW_DEBUG
|
||||
UTIL_AddDebugLine( vLast, vFinal, true, true );
|
||||
#endif // #ifdef DRAW_DEBUG
|
||||
UTIL_TraceLine( vLast, vFinal, MASK_SOLID, GetOuter(), ASW_COLLISION_GROUP_IGNORE_NPCS, &tr );
|
||||
if ( ( i == ( nSubdivisions - 1 ) && tr.fraction < 0.90 ) || ( i < ( nSubdivisions - 1 ) && tr.fraction != 1.0f ) )
|
||||
{
|
||||
BadLocation();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
vLast = vFinal;
|
||||
}
|
||||
|
||||
m_flBlockedAmount = -1.0f;
|
||||
}
|
||||
|
||||
|
||||
void CAI_ASW_MortarBehavior::LaunchMortar( )
|
||||
{
|
||||
#if 0
|
||||
trace_t tr;
|
||||
|
||||
UTIL_TraceLine( m_vMortarLocation + Vector( 0.0f, 0.0f, 25.0f ), m_vMortarLocation - Vector( 0.0f, 0.0f, 100.0f ), MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr );
|
||||
|
||||
if ( tr.allsolid == false )
|
||||
{
|
||||
UTIL_DecalTrace( &tr, "PaintSplatPink" );
|
||||
}
|
||||
#endif
|
||||
DispatchParticleEffect( "impact_mortar_preattack", m_vMortarLocation, QAngle( 0, 0, 0 ) );
|
||||
|
||||
CEffectData data;
|
||||
data.m_vOrigin = GetAbsOrigin();
|
||||
CPASFilter filter( data.m_vOrigin );
|
||||
filter.SetIgnorePredictionCull(true);
|
||||
DispatchParticleEffect( "mortar_launch", PATTACH_POINT_FOLLOW, GetOuter(), "mouth", false, -1, &filter );
|
||||
|
||||
Vector vVelocity;
|
||||
CalcVelocity( vVelocity );
|
||||
|
||||
int iAttachment = GetOuter()->LookupAttachment( "mouth" );
|
||||
Vector vecSpawn = GetAbsOrigin() + Vector( 0.0f, 0.0f, 15.0f );
|
||||
QAngle vecAngles = QAngle( 0.0f, 0.0f, 0.0f );
|
||||
if ( iAttachment > 0 )
|
||||
GetOuter()->GetAttachment( iAttachment, vecSpawn, vecAngles );
|
||||
|
||||
|
||||
// CASW_Mortar_Round *pGrenade =
|
||||
CASW_Mortar_Round::Mortar_Round_Create( m_flDamageAmount, m_flDamageRadius, 0, vecSpawn, vecAngles,
|
||||
vVelocity, AngularImpulse( 0.0f, 0.0f, 0.0f ), GetOuter() );
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose: routine called to start when a task initially starts
|
||||
// Input : pTask - the task structure
|
||||
//------------------------------------------------------------------------------
|
||||
void CAI_ASW_MortarBehavior::StartTask( const Task_t *pTask )
|
||||
{
|
||||
|
||||
switch( pTask->iTask )
|
||||
{
|
||||
case TASK_MORTAR_FIND_MORTAR_LOCATION:
|
||||
{
|
||||
FindMortarLocation();
|
||||
ValidateMortarLocation();
|
||||
break;
|
||||
}
|
||||
|
||||
case TASK_MORTAR_PREPARE_TO_FIRE:
|
||||
{
|
||||
GetOuter()->SetIdealActivity( ACT_PREP_TO_FIRE );
|
||||
break;
|
||||
}
|
||||
|
||||
case TASK_MORTAR_FIRE:
|
||||
{
|
||||
GetOuter()->SetIdealActivity( ACT_FIRE );
|
||||
// LaunchMortar();
|
||||
break;
|
||||
}
|
||||
|
||||
case TASK_MORTAR_FIRE_RECOVER:
|
||||
{
|
||||
GetOuter()->SetIdealActivity( ACT_FIRE_RECOVER );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
BaseClass::StartTask( pTask );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose: routine called every frame when a task is running
|
||||
// Input : pTask - the task structure
|
||||
//------------------------------------------------------------------------------
|
||||
void CAI_ASW_MortarBehavior::RunTask( const Task_t *pTask )
|
||||
{
|
||||
switch( pTask->iTask )
|
||||
{
|
||||
case TASK_MORTAR_FIND_MORTAR_LOCATION:
|
||||
{
|
||||
TaskComplete();
|
||||
m_flDeferUntil = gpGlobals->curtime + m_flFireRate;
|
||||
break;
|
||||
}
|
||||
|
||||
case TASK_MORTAR_PREPARE_TO_FIRE:
|
||||
{
|
||||
if ( !GetOuter()->FInAimCone( m_vMortarLocation ) )
|
||||
{
|
||||
GetMotor()->SetIdealYawToTargetAndUpdate( m_vMortarLocation, AI_KEEP_YAW_SPEED );
|
||||
}
|
||||
|
||||
if ( GetOuter()->IsActivityFinished() )
|
||||
{
|
||||
TaskComplete();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TASK_MORTAR_FIRE:
|
||||
{
|
||||
if ( GetOuter()->IsActivityFinished() )
|
||||
{
|
||||
TaskComplete();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TASK_MORTAR_FIRE_RECOVER:
|
||||
{
|
||||
if ( GetOuter()->IsActivityFinished() )
|
||||
{
|
||||
TaskComplete();
|
||||
}
|
||||
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_MortarBehavior::SelectSchedule()
|
||||
{
|
||||
return SCHED_MORTAR_MOVE_TO_FIRE_SPOT;
|
||||
}
|
||||
|
||||
|
||||
AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( CAI_ASW_MortarBehavior )
|
||||
|
||||
DECLARE_TASK( TASK_MORTAR_FIND_MORTAR_LOCATION )
|
||||
DECLARE_TASK( TASK_MORTAR_PREPARE_TO_FIRE )
|
||||
DECLARE_TASK( TASK_MORTAR_FIRE )
|
||||
DECLARE_TASK( TASK_MORTAR_FIRE_RECOVER )
|
||||
|
||||
DEFINE_SCHEDULE
|
||||
(
|
||||
SCHED_MORTAR_MOVE_TO_FIRE_SPOT,
|
||||
" Tasks"
|
||||
" TASK_MORTAR_FIND_MORTAR_LOCATION 0"
|
||||
" TASK_MORTAR_PREPARE_TO_FIRE 0"
|
||||
" TASK_MORTAR_FIRE 0"
|
||||
" TASK_MORTAR_FIRE_RECOVER 0"
|
||||
// " TASK_WAIT 0.5"
|
||||
""
|
||||
" Interrupts"
|
||||
" COND_TASK_FAILED"
|
||||
);
|
||||
|
||||
AI_END_CUSTOM_SCHEDULE_PROVIDER()
|
||||
|
||||
#include "tier0/memdbgoff.h"
|
||||
Reference in New Issue
Block a user