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,462 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: NPC does a pounce attack against his enemy when close enough. Uses MeleeAttack2Conditions.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "beam_shared.h"
|
||||
#include "ai_motor.h"
|
||||
#include "asw_ai_behavior_pounce.h"
|
||||
#include "ai_hint.h"
|
||||
#include "ai_navigator.h"
|
||||
#include "ai_memory.h"
|
||||
#include "asw_alien.h"
|
||||
#include "asw_marine.h"
|
||||
#include "asw_gamerules.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
BEGIN_DATADESC( CAI_ASW_PounceBehavior )
|
||||
END_DATADESC();
|
||||
|
||||
LINK_BEHAVIOR_TO_CLASSNAME( CAI_ASW_PounceBehavior );
|
||||
|
||||
Activity ACT_ALIEN_POUNCE;
|
||||
Activity ACT_ALIEN_POUNCE_HIT;
|
||||
Activity ACT_ALIEN_POUNCE_MISS;
|
||||
|
||||
#define POUNCE_THINK_CONTEXT "PounceThinkContext"
|
||||
|
||||
extern ConVar sv_gravity;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose: constructor
|
||||
//------------------------------------------------------------------------------
|
||||
CAI_ASW_PounceBehavior::CAI_ASW_PounceBehavior( )
|
||||
{
|
||||
m_flMinRange = 0.0f;
|
||||
m_flMaxRange = 100.0f;
|
||||
m_flAttackDotAngle = 0.7f;
|
||||
m_flPounceInterval = 0.0f;
|
||||
m_flNextPounceTime = 0.0f;
|
||||
m_flPounceDistance = 300.0f;
|
||||
m_flPounceDamage = 15.0f;
|
||||
m_flIgnoreWorldCollisionTime = 0.0f;
|
||||
m_bMidPounce = false;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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_PounceBehavior::KeyValue( const char *szKeyName, const char *szValue )
|
||||
{
|
||||
if ( V_stricmp( szKeyName, "min_range" ) == 0 )
|
||||
{
|
||||
m_flMinRange = atof( szValue );
|
||||
return true;
|
||||
}
|
||||
else if ( V_stricmp( szKeyName, "max_range" ) == 0 )
|
||||
{
|
||||
m_flMaxRange = atof( szValue );
|
||||
return true;
|
||||
}
|
||||
else if ( V_stricmp( szKeyName, "attack_dot_angle" ) == 0 )
|
||||
{
|
||||
m_flAttackDotAngle = atof( szValue );
|
||||
return true;
|
||||
}
|
||||
else if ( V_stricmp( szKeyName, "pounce_interval" ) == 0 )
|
||||
{
|
||||
m_flPounceInterval = atof( szValue );
|
||||
return true;
|
||||
}
|
||||
else if ( V_stricmp( szKeyName, "pounce_distance" ) == 0 )
|
||||
{
|
||||
m_flPounceDistance = atof( szValue );
|
||||
return true;
|
||||
}
|
||||
else if ( V_stricmp( szKeyName, "pounce_damage" ) == 0 )
|
||||
{
|
||||
m_flPounceDamage = atof( szValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return BaseClass::KeyValue( szKeyName, szValue );
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose: precaches any additional assets this behavior needs
|
||||
//------------------------------------------------------------------------------
|
||||
void CAI_ASW_PounceBehavior::Precache( void )
|
||||
{
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//------------------------------------------------------------------------------
|
||||
void CAI_ASW_PounceBehavior::Init( )
|
||||
{
|
||||
CASW_Alien *pNPC = static_cast< CASW_Alien * >( GetOuter() );
|
||||
if ( !pNPC )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pNPC->meleeAttack2.Init( m_flMinRange, m_flMaxRange, m_flAttackDotAngle, true );
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose: determines if we can use this behavior currently
|
||||
// Output : returns true if this behavior is able to run
|
||||
//------------------------------------------------------------------------------
|
||||
bool CAI_ASW_PounceBehavior::CanSelectSchedule()
|
||||
{
|
||||
if ( !GetOuter()->IsInterruptable() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( gpGlobals->curtime < m_flNextPounceTime )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !HasCondition( COND_CAN_MELEE_ATTACK2 ) && !HasCondition( COND_TOO_CLOSE_TO_ATTACK ) )
|
||||
{
|
||||
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_PounceBehavior::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_PounceBehavior::GatherConditionsNotActive( )
|
||||
{
|
||||
BaseClass::GatherConditionsNotActive();
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose: general purpose routine to collect conditions used both during active
|
||||
// and non-active states of the behavior.
|
||||
//------------------------------------------------------------------------------
|
||||
void CAI_ASW_PounceBehavior::GatherCommonConditions( )
|
||||
{
|
||||
BaseClass::GatherCommonConditions();
|
||||
}
|
||||
|
||||
|
||||
void CAI_ASW_PounceBehavior::BeginScheduleSelection( )
|
||||
{
|
||||
SetBehaviorParam( m_StatusParm, -1 );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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_PounceBehavior::SelectSchedule()
|
||||
{
|
||||
if ( HasCondition(COND_TOO_CLOSE_TO_ATTACK) )
|
||||
return SCHED_BACK_AWAY_FROM_ENEMY;
|
||||
|
||||
m_flNextPounceTime = gpGlobals->curtime + m_flPounceInterval;
|
||||
|
||||
return SCHED_ALIEN_POUNCE;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input :
|
||||
// Output :
|
||||
//------------------------------------------------------------------------------
|
||||
void CAI_ASW_PounceBehavior::HandleBehaviorEvent( CBaseEntity *pInflictor, BehaviorEvent_t eEvent, int nParm )
|
||||
{
|
||||
switch( eEvent )
|
||||
{
|
||||
case BEHAVIOR_EVENT_POUNCE:
|
||||
{
|
||||
CASW_Alien *pOwner = static_cast< CASW_Alien * >( GetOuter() );
|
||||
|
||||
if ( pOwner->GetEnemy() )
|
||||
{
|
||||
// jump straight ahead
|
||||
Vector vecForward;
|
||||
AngleVectors( pOwner->EyeAngles(), &vecForward );
|
||||
vecForward.z = 0;
|
||||
vecForward.NormalizeInPlace();
|
||||
PounceAttack( false, GetAbsOrigin() + vecForward * m_flPounceDistance );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define ALIEN_IGNORE_WORLD_COLLISION_TIME 0.5
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Does a jump attack at the given position.
|
||||
// Input : bRandomJump - Just hop in a random direction.
|
||||
// vecPos - Position to jump at, ignored if bRandom is set to true.
|
||||
// bThrown -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAI_ASW_PounceBehavior::PounceAttack( bool bRandomJump, const Vector &vecPos, bool bThrown, float flBaseHeight, float flAdditionalHeight )
|
||||
{
|
||||
Vector vecJumpVel;
|
||||
if ( !bRandomJump )
|
||||
{
|
||||
float gravity = sv_gravity.GetFloat();
|
||||
if ( gravity <= 1 )
|
||||
{
|
||||
gravity = 1;
|
||||
}
|
||||
|
||||
// How fast does the headcrab need to travel to reach the position given gravity?
|
||||
float flActualHeight = vecPos.z - GetAbsOrigin().z;
|
||||
float height = flActualHeight;
|
||||
if ( height < 16 )
|
||||
{
|
||||
height = flBaseHeight; //60; //16;
|
||||
}
|
||||
else
|
||||
{
|
||||
float flMaxHeight = bThrown ? 400 : 120;
|
||||
if ( height > flMaxHeight )
|
||||
{
|
||||
height = flMaxHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// overshoot the jump by an additional 8 inches
|
||||
// NOTE: This calculation jumps at a position INSIDE the box of the enemy (player)
|
||||
// so if you make the additional height too high, the crab can land on top of the
|
||||
// enemy's head. If we want to jump high, we'll need to move vecPos to the surface/outside
|
||||
// of the enemy's box.
|
||||
|
||||
float additionalHeight = 0;
|
||||
if ( height < 32 )
|
||||
{
|
||||
additionalHeight = flAdditionalHeight;
|
||||
}
|
||||
|
||||
height += additionalHeight;
|
||||
|
||||
// NOTE: This equation here is from vf^2 = vi^2 + 2*a*d
|
||||
float speed = sqrt( 2 * gravity * height );
|
||||
float time = speed / gravity;
|
||||
|
||||
// add in the time it takes to fall the additional height
|
||||
// So the impact takes place on the downward slope at the original height
|
||||
time += sqrt( (2 * additionalHeight) / gravity );
|
||||
|
||||
// Scale the sideways velocity to get there at the right time
|
||||
VectorSubtract( vecPos, GetAbsOrigin(), vecJumpVel );
|
||||
vecJumpVel /= time;
|
||||
|
||||
// Speed to offset gravity at the desired height.
|
||||
vecJumpVel.z = speed;
|
||||
|
||||
// Don't jump too far/fast.
|
||||
float flJumpSpeed = vecJumpVel.Length();
|
||||
float flMaxSpeed = bThrown ? 1000.0f : 650.0f;
|
||||
if ( flJumpSpeed > flMaxSpeed )
|
||||
{
|
||||
vecJumpVel *= flMaxSpeed / flJumpSpeed;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Jump hop, don't care where.
|
||||
//
|
||||
Vector forward, up;
|
||||
AngleVectors( GetLocalAngles(), &forward, NULL, &up );
|
||||
vecJumpVel = Vector( forward.x, forward.y, up.z ) * 350;
|
||||
}
|
||||
|
||||
//AttackSound();
|
||||
Leap( vecJumpVel );
|
||||
}
|
||||
|
||||
void CAI_ASW_PounceBehavior::Leap( const Vector &vecVel )
|
||||
{
|
||||
m_bMidPounce = true;
|
||||
|
||||
SetCondition( COND_FLOATING_OFF_GROUND );
|
||||
SetGroundEntity( NULL );
|
||||
|
||||
m_flIgnoreWorldCollisionTime = gpGlobals->curtime + ALIEN_IGNORE_WORLD_COLLISION_TIME;
|
||||
|
||||
if( HasHeadroom() )
|
||||
{
|
||||
// Take him off ground so engine doesn't instantly reset FL_ONGROUND.
|
||||
UTIL_SetOrigin( GetOuter(), GetLocalOrigin() + Vector( 0, 0, 1 ) );
|
||||
}
|
||||
|
||||
GetOuter()->SetAbsVelocity( vecVel );
|
||||
|
||||
// think every frame so the player sees the alien where it is
|
||||
|
||||
GetOuter()->SetContextThink( &CASW_Alien::CallBehaviorThink, gpGlobals->curtime, POUNCE_THINK_CONTEXT );
|
||||
}
|
||||
|
||||
bool CAI_ASW_PounceBehavior::HasHeadroom()
|
||||
{
|
||||
trace_t tr;
|
||||
UTIL_TraceEntity( GetOuter(), GetAbsOrigin(), GetAbsOrigin() + Vector( 0, 0, 1 ), MASK_NPCSOLID, GetOuter(), GetCollisionGroup(), &tr );
|
||||
|
||||
return (tr.fraction == 1.0);
|
||||
}
|
||||
|
||||
void CAI_ASW_PounceBehavior::BehaviorThink( void )
|
||||
{
|
||||
if( GetOuter()->GetFlags() & FL_ONGROUND && gpGlobals->curtime >= m_flIgnoreWorldCollisionTime )
|
||||
{
|
||||
GetOuter()->SetAbsVelocity( vec3_origin );
|
||||
|
||||
GetOuter()->SetContextThink( NULL, TICK_NEVER_THINK, POUNCE_THINK_CONTEXT );
|
||||
return;
|
||||
}
|
||||
|
||||
GetOuter()->SetContextThink( &CASW_Alien::CallBehaviorThink, gpGlobals->curtime, POUNCE_THINK_CONTEXT );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: LeapTouch - this is the headcrab's touch function when it is in the air.
|
||||
// Input : *pOther -
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CAI_ASW_PounceBehavior::StartTouch( CBaseEntity *pOther )
|
||||
{
|
||||
BaseClass::StartTouch( pOther );
|
||||
|
||||
if ( !m_bMidPounce )
|
||||
return;
|
||||
|
||||
if ( !pOther->ShouldCollide( GetCollisionGroup(), GetOuter()->PhysicsSolidMaskForEntity() ) )
|
||||
return;
|
||||
|
||||
if ( !g_pGameRules->ShouldCollide( GetCollisionGroup(), pOther->GetCollisionGroup() ) )
|
||||
return;
|
||||
|
||||
bool bHit = false;
|
||||
if ( GetOuter()->IRelationType( pOther ) == D_HT )
|
||||
{
|
||||
if ( pOther->m_takedamage != DAMAGE_NO && !pOther->IsWorld() )
|
||||
{
|
||||
Vector vecForceDir = GetOuter()->GetAbsVelocity();
|
||||
vecForceDir.NormalizeInPlace();
|
||||
// TODO: Check they're not behind me
|
||||
CASW_Marine *pMarine = CASW_Marine::AsMarine( pOther );
|
||||
if ( pMarine )
|
||||
{
|
||||
pMarine->Stumble( GetOuter(), vecForceDir, false );
|
||||
}
|
||||
|
||||
float flDamage = ASWGameRules()->ModifyAlienDamageBySkillLevel( m_flPounceDamage );
|
||||
flDamage = MAX( flDamage, 1.0f );
|
||||
|
||||
CTakeDamageInfo info( GetOuter(), GetOuter(), flDamage, DMG_SLASH );
|
||||
const trace_t &touchTrace = GetOuter()->GetTouchTrace();
|
||||
CalculateMeleeDamageForce( &info, vecForceDir, touchTrace.endpos );
|
||||
pOther->TakeDamage( info );
|
||||
|
||||
bHit = true;
|
||||
}
|
||||
}
|
||||
else if( !(GetOuter()->GetFlags() & FL_ONGROUND) )
|
||||
{
|
||||
// Still in the air...
|
||||
if( gpGlobals->curtime < m_flIgnoreWorldCollisionTime )
|
||||
{
|
||||
// Headcrabs try to ignore the world, static props, and friends for a
|
||||
// fraction of a second after they jump. This is because they often brush
|
||||
// doorframes or props as they leap, and touching those objects turns off
|
||||
// this touch function, which can cause them to hit the player and not bite.
|
||||
// A timer probably isn't the best way to fix this, but it's one of our
|
||||
// safer options at this point (sjb).
|
||||
return;
|
||||
}
|
||||
|
||||
if( !pOther->IsSolid() )
|
||||
{
|
||||
// Touching a trigger or something.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GetOuter()->SetAbsVelocity( vec3_origin );
|
||||
|
||||
if ( bHit )
|
||||
{
|
||||
if ( GetOuter()->HaveSequenceForActivity( (Activity) ACT_ALIEN_POUNCE_HIT ) )
|
||||
{
|
||||
GetOuter()->SetActivity( (Activity) ACT_ALIEN_POUNCE_HIT );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( GetOuter()->HaveSequenceForActivity( (Activity) ACT_ALIEN_POUNCE_MISS ) )
|
||||
{
|
||||
GetOuter()->SetActivity( (Activity) ACT_ALIEN_POUNCE_MISS );
|
||||
}
|
||||
}
|
||||
|
||||
// make sure we're solid
|
||||
GetOuter()->RemoveSolidFlags( FSOLID_NOT_SOLID );
|
||||
|
||||
m_bMidPounce = false;
|
||||
}
|
||||
|
||||
AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( CAI_ASW_PounceBehavior )
|
||||
|
||||
DECLARE_ACTIVITY( ACT_ALIEN_POUNCE )
|
||||
DECLARE_ACTIVITY( ACT_ALIEN_POUNCE_HIT )
|
||||
DECLARE_ACTIVITY( ACT_ALIEN_POUNCE_MISS )
|
||||
|
||||
// forward pounce attack
|
||||
DEFINE_SCHEDULE
|
||||
(
|
||||
SCHED_ALIEN_POUNCE,
|
||||
|
||||
" Tasks"
|
||||
" TASK_STOP_MOVING 0"
|
||||
" TASK_FACE_ENEMY 0"
|
||||
" TASK_ANNOUNCE_ATTACK 1"
|
||||
" TASK_RESET_ACTIVITY 0"
|
||||
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_ALIEN_POUNCE"
|
||||
|
||||
" Interrupts"
|
||||
" COND_TASK_FAILED"
|
||||
)
|
||||
|
||||
AI_END_CUSTOM_SCHEDULE_PROVIDER()
|
||||
|
||||
#include "tier0/memdbgoff.h"
|
||||
Reference in New Issue
Block a user