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.

815 lines
21 KiB

#include "cbase.h"
#include "asw_alien_jumper.h"
#include "ai_route.h"
#include "ai_hint.h"
#include "ai_memory.h"
#include "ai_moveprobe.h"
#include "npcevent.h"
#include "IEffects.h"
#include "ndebugoverlay.h"
#include "soundent.h"
#include "soundenvelope.h"
#include "ai_squad.h"
#include "ai_network.h"
#include "ai_pathfinder.h"
#include "ai_navigator.h"
#include "ai_senses.h"
#include "npc_rollermine.h"
#include "ai_blended_movement.h"
#include "physics_prop_ragdoll.h"
#include "iservervehicle.h"
#include "player_pickup.h"
#include "props.h"
#include "antlion_dust.h"
#include "decals.h"
#include "prop_combine_ball.h"
#include "eventqueue.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ConVar asw_test_new_alien_jump( "asw_test_new_alien_jump", "1", FCVAR_ARCHIVE );
extern ConVar asw_debug_aliens;
extern ConVar sv_gravity;
int AE_ASW_ALIEN_START_JUMP;
int AE_ASW_ALIEN_GLIDE;
#define ANTLION_JUMP_MIN 128.0f
#define ANTLION_JUMP_MAX_RISE 512.0f
#define ANTLION_JUMP_MAX 1024.0f
enum
{
SQUAD_SLOT_ALIEN_JUMP = LAST_SHARED_SQUADSLOT,
};
int ACT_ASW_ALIEN_JUMP_START;
int ACT_ASW_ALIEN_LAND;
CASW_Alien_Jumper::CASW_Alien_Jumper()
{
m_flJumpTime = 0.0f;
m_flNextJumpPushTime = 0.0f;
m_vecLastJumpAttempt.Init();
m_vecSavedJump.Init();
m_bForcedStuckJump = false;
}
LINK_ENTITY_TO_CLASS( asw_alien_jumper, CASW_Alien_Jumper );
BEGIN_DATADESC( CASW_Alien_Jumper )
DEFINE_FIELD( m_flJumpTime, FIELD_TIME ),
DEFINE_FIELD( m_vecSavedJump, FIELD_VECTOR ),
DEFINE_FIELD( m_vecLastJumpAttempt, FIELD_VECTOR ),
DEFINE_FIELD( m_bDisableJump, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flNextJumpPushTime, FIELD_TIME ),
DEFINE_FIELD( m_bForcedStuckJump, FIELD_BOOLEAN ),
DEFINE_FIELD( m_bTriggerJumped, FIELD_BOOLEAN ),
DEFINE_INPUTFUNC( FIELD_VOID, "EnableJump", InputEnableJump ),
DEFINE_INPUTFUNC( FIELD_VOID, "DisableJump", InputDisableJump ),
END_DATADESC()
void CASW_Alien_Jumper::Spawn()
{
BaseClass::Spawn();
CapabilitiesAdd( bits_CAP_MOVE_JUMP );
m_bDisableJump = false;
}
void CASW_Alien_Jumper::ManageFleeCapabilities( bool bEnable )
{
if ( bEnable == false )
{
//Remove the jump capabilty when we build our route.
//We'll enable it back again after the route has been built.
CapabilitiesRemove( bits_CAP_MOVE_JUMP );
if ( HasSpawnFlags( SF_ANTLION_USE_GROUNDCHECKS ) == false )
CapabilitiesRemove( bits_CAP_SKIP_NAV_GROUND_CHECK );
}
else
{
if ( m_bDisableJump == false )
CapabilitiesAdd( bits_CAP_MOVE_JUMP );
if ( HasSpawnFlags( SF_ANTLION_USE_GROUNDCHECKS ) == false )
CapabilitiesAdd( bits_CAP_SKIP_NAV_GROUND_CHECK );
}
}
void CASW_Alien_Jumper::HandleAnimEvent( animevent_t *pEvent )
{
int nEvent = pEvent->Event();
if ( nEvent == AE_ASW_ALIEN_START_JUMP )
{
StartJump();
return;
}
else if ( nEvent == AE_ASW_ALIEN_GLIDE )
{
SetActivity(ACT_GLIDE);
return;
}
BaseClass::HandleAnimEvent( pEvent );
}
bool CASW_Alien_Jumper::IsUnusableNode(int iNodeID, CAI_Hint *pHint)
{
bool iBaseReturn = BaseClass::IsUnusableNode( iNodeID, pHint );
if ( asw_test_new_alien_jump.GetBool() == 0 )
return iBaseReturn;
CAI_Node *pNode = GetNavigator()->GetNetwork()->GetNode( iNodeID );
if ( pNode )
{
if ( pNode->IsLocked() )
return true;
}
return iBaseReturn;
}
void CASW_Alien_Jumper::LockJumpNode( void )
{
if ( HasSpawnFlags( SF_ANTLION_USE_GROUNDCHECKS ) == false )
return;
if ( GetNavigator()->GetPath() == NULL )
return;
if ( asw_test_new_alien_jump.GetBool() == false )
return;
AI_Waypoint_t *pWaypoint = GetNavigator()->GetPath()->GetCurWaypoint();
while ( pWaypoint )
{
AI_Waypoint_t *pNextWaypoint = pWaypoint->GetNext();
if ( pNextWaypoint && pNextWaypoint->NavType() == NAV_JUMP && pWaypoint->iNodeID != NO_NODE )
{
CAI_Node *pNode = GetNavigator()->GetNetwork()->GetNode( pWaypoint->iNodeID );
if ( pNode )
{
//NDebugOverlay::Box( pNode->GetOrigin(), Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 255, 0, 0, 0, 2 );
pNode->Lock( 0.5f );
break;
}
}
else
{
pWaypoint = pWaypoint->GetNext();
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CASW_Alien_Jumper::OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult )
{
bool iBaseReturn = BaseClass::OnObstructionPreSteer( pMoveGoal, distClear, pResult );
if ( asw_test_new_alien_jump.GetBool() == false )
return iBaseReturn;
if ( HasSpawnFlags( SF_ANTLION_USE_GROUNDCHECKS ) == false )
return iBaseReturn;
CAI_BaseNPC *pBlocker = pMoveGoal->directTrace.pObstruction->MyNPCPointer();
// push other jumpers out of the way?
if ( pBlocker && pBlocker->Classify() == CLASS_ASW_DRONE )
{
// HACKHACK
CASW_Alien_Jumper *pJumper = dynamic_cast< CASW_Alien_Jumper * > ( pBlocker );
if ( pJumper )
{
if ( pJumper->AllowedToBePushed() == true && GetEnemy() == NULL )
{
//NDebugOverlay::Box( pAntlion->GetAbsOrigin(), GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 2 );
pJumper->GetMotor()->SetIdealYawToTarget( WorldSpaceCenter() );
pJumper->SetSchedule( SCHED_MOVE_AWAY );
pJumper->m_flNextJumpPushTime = gpGlobals->curtime + 2.0f;
}
}
}
return iBaseReturn;
}
bool CASW_Alien_Jumper::AllowedToBePushed( void )
{
if ( IsMoving() == false
&& GetNavType() != NAV_JUMP && m_flNextJumpPushTime <= gpGlobals->curtime )
{
return true;
}
return false;
}
void CASW_Alien_Jumper::StartTask( const Task_t *pTask )
{
switch ( pTask->iTask )
{
case TASK_ASW_ALIEN_FACE_JUMP:
break;
case TASK_ASW_ALIEN_JUMP:
if ( CheckLanding() )
{
TaskComplete();
}
break;
case TASK_ASW_ALIEN_RETRY_JUMP:
{
if (!DoJumpTo(m_vecLastJumpAttempt))
WaitAndRetryJump(m_vecLastJumpAttempt);
}
break;
default:
BaseClass::StartTask( pTask );
break;
}
}
void CASW_Alien_Jumper::RunTask( const Task_t *pTask )
{
switch ( pTask->iTask )
{
case TASK_ASW_ALIEN_FACE_JUMP:
{
Vector jumpDir = m_vecSavedJump;
VectorNormalize( jumpDir );
QAngle jumpAngles;
VectorAngles( jumpDir, jumpAngles );
GetMotor()->SetIdealYawAndUpdate( jumpAngles[YAW], AI_KEEP_YAW_SPEED );
SetTurnActivity();
if ( abs(GetMotor()->DeltaIdealYaw()) < 2 )
{
//Msg("Alien jumping: jumpyaw=%f delta=%f ang.y=%f\n",
//jumpAngles[YAW], GetMotor()->DeltaIdealYaw(), GetLocalAngles().y);
TaskComplete();
}
}
break;
case TASK_ASW_ALIEN_JUMP:
if ( CheckLanding() )
{
TaskComplete();
}
break;
default:
BaseClass::RunTask( pTask );
break;
}
}
// Purpose: Returns true if a reasonable jumping distance
bool CASW_Alien_Jumper::IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos ) const
{
const float MAX_JUMP_RISE = 512;
//const float MIN_JUMP_RISE = 16;
const float MAX_JUMP_DROP = 512;
const float MAX_JUMP_DISTANCE = 1024;
const float MIN_JUMP_DISTANCE = 128;
// make sure we don't do really flat jumps
//float fHeight = (apex.z - startPos.z);
//Msg("checking legality of jump with height %f\n", fHeight);
//if ((apex.z - startPos.z) < 10 || fHeight != 0)
//return false;
//Adrian: Don't try to jump if my destination is right next to me.
if ( ( endPos - GetAbsOrigin()).Length() < MIN_JUMP_DISTANCE )
return false;
if ( HasSpawnFlags( SF_ANTLION_USE_GROUNDCHECKS ) && asw_test_new_alien_jump.GetBool() == true )
{
trace_t tr;
AI_TraceHull( endPos, endPos, GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr );
if ( tr.m_pEnt )
{
CAI_BaseNPC *pBlocker = tr.m_pEnt->MyNPCPointer();
if ( pBlocker && pBlocker->Classify() == CLASS_ASW_DRONE )
{
// HACKHACK - push other jumpers out of the way
CASW_Alien_Jumper *pJumper = dynamic_cast< CASW_Alien_Jumper * > ( pBlocker );
if ( pJumper )
{
if ( pJumper->AllowedToBePushed() == true )
{
// NDebugOverlay::Line( GetAbsOrigin(), endPos, 255, 0, 0, 0, 2 );
// NDebugOverlay::Box( pAntlion->GetAbsOrigin(), GetHullMins(), GetHullMaxs(), 0, 0, 255, 0, 2 );
pJumper->GetMotor()->SetIdealYawToTarget( endPos );
pJumper->SetSchedule( SCHED_MOVE_AWAY );
pJumper->m_flNextJumpPushTime = gpGlobals->curtime + 2.0f;
}
}
}
}
}
return BaseClass::IsJumpLegal( startPos, apex, endPos, MAX_JUMP_RISE, MAX_JUMP_DROP, MAX_JUMP_DISTANCE );
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CASW_Alien_Jumper::ShouldJump( void )
{
if ( GetEnemy() == NULL )
return false;
// don't jump if we're stunned
if (m_bElectroStunned)
return false;
//Too soon to try to jump
if ( m_flJumpTime > gpGlobals->curtime )
return false;
// only jump if you're on the ground
if (!(GetFlags() & FL_ONGROUND) || GetNavType() == NAV_JUMP )
return false;
// Don't jump if I'm not allowed
if ( ( CapabilitiesGet() & bits_CAP_MOVE_JUMP ) == false )
return false;
Vector vEnemyForward, vForward;
GetEnemy()->GetVectors( &vEnemyForward, NULL, NULL );
GetVectors( &vForward, NULL, NULL );
float flDot = DotProduct( vForward, vEnemyForward );
if ( flDot < 0.5f )
flDot = 0.5f;
Vector vecPredictedPos;
//Get our likely position in two seconds
UTIL_PredictedPosition( GetEnemy(), flDot * 2.5f, &vecPredictedPos );
// Don't jump if we're already near the target
if ( ( GetAbsOrigin() - vecPredictedPos ).LengthSqr() < (512*512) )
return false;
//Don't retest if the target hasn't moved enough
//FIXME: Check your own distance from last attempt as well
if ( ( ( m_vecLastJumpAttempt - vecPredictedPos ).LengthSqr() ) < (128*128) )
{
m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f );
return false;
}
Vector targetDir = ( vecPredictedPos - GetAbsOrigin() );
float flDist = VectorNormalize( targetDir );
// don't jump at target it it's very close
if (flDist < ANTLION_JUMP_MIN)
return false;
Vector targetPos = vecPredictedPos + ( targetDir * (GetHullWidth()*4.0f) );
// Try the jump
AIMoveTrace_t moveTrace;
GetMoveProbe()->MoveLimit( NAV_JUMP, GetAbsOrigin(), targetPos, MASK_NPCSOLID, GetNavTargetEntity(), &moveTrace );
//See if it succeeded
if ( IsMoveBlocked( moveTrace.fStatus ) )
{
if ( asw_debug_aliens.GetInt() == 2 )
{
NDebugOverlay::Box( targetPos, GetHullMins(), GetHullMaxs(), 255, 0, 0, 0, 5 );
NDebugOverlay::Line( GetAbsOrigin(), targetPos, 255, 0, 0, 0, 5 );
}
m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f );
return false;
}
if ( asw_debug_aliens.GetInt() == 2 )
{
NDebugOverlay::Box( targetPos, GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 5 );
NDebugOverlay::Line( GetAbsOrigin(), targetPos, 0, 255, 0, 0, 5 );
}
//Save this jump in case the next time fails
m_vecSavedJump = moveTrace.vJumpVelocity;
m_vecLastJumpAttempt = targetPos;
return true;
}
// note: mostly copied from shover parent (no clean way to call up and extend), with the jump part added
int CASW_Alien_Jumper::SelectCombatSchedule( void )
{
//Physics target
if ( HasCondition( COND_ALIEN_SHOVER_PHYSICS_TARGET ) )
{
//Msg("Alien shoving physics object from selectcombatschedule\n");
return SCHED_ALIEN_SHOVER_PHYSICS_ATTACK;
}
// Attack if we can
if ( HasCondition(COND_CAN_MELEE_ATTACK1) )
return SCHED_MELEE_ATTACK1;
// See if we can bash what's in our way, or roar
if ( HasCondition( COND_ENEMY_UNREACHABLE ) )
{
int iUnreach = SelectUnreachableSchedule();
if (iUnreach != -1)
return iUnreach;
}
// Try to jump
if ( HasCondition( COND_ASW_ALIEN_CAN_JUMP ) )
return SCHED_ASW_ALIEN_JUMP;
return BaseClass::BaseClass::SelectSchedule();
}
void CASW_Alien_Jumper::StartJump( void )
{
if ( m_bForcedStuckJump == false )
{
//Must be jumping at an enemy
if ( GetEnemy() == NULL )
return;
//Don't jump if we're not on the ground
if ( ( GetFlags() & FL_ONGROUND ) == false )
return;
}
//Take us off the ground
SetGroundEntity( NULL );
//Msg("Drone doing jump vec %f %f %f\n", m_vecSavedJump.x, m_vecSavedJump.y, m_vecSavedJump.z);
SetAbsVelocity( m_vecSavedJump );
m_bForcedStuckJump = false;
//Setup our jump time so that we don't try it again too soon
m_flJumpTime = gpGlobals->curtime + random->RandomInt( 2, 6 );
}
// Purpose: Monitor the antlion's jump to play the proper landing sequence
bool CASW_Alien_Jumper::CheckLanding( void )
{
trace_t tr;
Vector testPos;
//Amount of time to predict forward
const float timeStep = 0.1f;
//Roughly looks one second into the future
testPos = GetAbsOrigin() + ( GetAbsVelocity() * timeStep );
testPos[2] -= ( 0.5 * sv_gravity.GetFloat() * GetGravity() * timeStep * timeStep);
if ( asw_debug_aliens.GetInt() == 2 )
{
NDebugOverlay::Line( GetAbsOrigin(), testPos, 255, 0, 0, 0, 0.5f );
NDebugOverlay::Cross3D( m_vecSavedJump, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, true, 0.5f );
}
// Look below
AI_TraceHull( GetAbsOrigin(), testPos, NAI_Hull::Mins( GetHullType() ), NAI_Hull::Maxs( GetHullType() ), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr );
//See if we're about to contact, or have already contacted the ground
if ( ( tr.fraction != 1.0f ) || ( GetFlags() & FL_ONGROUND ) )
{
int sequence = SelectWeightedSequence( (Activity)ACT_ASW_ALIEN_LAND );
if ( GetSequence() != sequence )
{
VacateStrategySlot();
SetIdealActivity( (Activity) ACT_ASW_ALIEN_LAND );
CreateDust( false );
EmitSound( "ASW_Drone.Land" );
// asw todo: make the alien attack here?
//if ( GetEnemy() && GetEnemy()->IsPlayer() )
//{
//CBasePlayer *pPlayer = ToBasePlayer( GetEnemy() );
//if ( pPlayer && pPlayer->IsInAVehicle() == false )
//MeleeAttack( ANTLION_MELEE1_RANGE, sk_antlion_swipe_damage.GetFloat(), QAngle( 4.0f, 0.0f, 0.0f ), Vector( -250.0f, 1.0f, 1.0f ) );
//}
SetAbsVelocity( GetAbsVelocity() * 0.33f );
return false;
}
return IsActivityFinished();
}
return false;
}
void CASW_Alien_Jumper::CreateDust( bool placeDecal )
{
trace_t tr;
AI_TraceLine( GetAbsOrigin()+Vector(0,0,1), GetAbsOrigin()-Vector(0,0,64), MASK_SOLID_BRUSHONLY | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP, this, COLLISION_GROUP_NONE, &tr );
if ( tr.fraction < 1.0f )
{
surfacedata_t *pdata = physprops->GetSurfaceData( tr.surface.surfaceProps );
if ( ( pdata->game.material == CHAR_TEX_CONCRETE ) ||
( pdata->game.material == CHAR_TEX_DIRT ) ||
( pdata->game.material == CHAR_TEX_SAND ) )
{
UTIL_CreateAntlionDust( tr.endpos + Vector(0,0,24), GetAbsAngles() );
if ( placeDecal )
{
UTIL_DecalTrace( &tr, "Antlion.Unburrow" );
}
}
}
}
void CASW_Alien_Jumper::BuildScheduleTestBits( void )
{
//Don't allow any modifications when scripted
if ( m_NPCState == NPC_STATE_SCRIPT )
return;
BaseClass::BuildScheduleTestBits();
//Make sure we interrupt a run schedule if we can jump
if ( IsCurSchedule(SCHED_CHASE_ENEMY) && GetNavType() == NAV_GROUND )
{
SetCustomInterruptCondition( COND_ASW_ALIEN_CAN_JUMP );
SetCustomInterruptCondition( COND_ENEMY_UNREACHABLE );
}
//Interrupt any schedule unless already fleeing, burrowing, burrowed, or unburrowing.
if(!IsCurSchedule(SCHED_ASW_ALIEN_JUMP) &&
( GetFlags() & FL_ONGROUND ) )
{
// Only do these if not jumping as well
if (!IsCurSchedule(SCHED_ASW_ALIEN_JUMP))
{
if ( GetEnemy() == NULL )
{
SetCustomInterruptCondition( COND_HEAR_PHYSICS_DANGER );
}
//if ( GetNavType() != NAV_JUMP )
//SetCustomInterruptCondition( COND_ANTLION_RECEIVED_ORDERS );
}
//SetCustomInterruptCondition( COND_ANTLION_ON_NPC );
}
}
void CASW_Alien_Jumper::PrescheduleThink( void )
{
//New Enemy? Try to jump at him.
if ( HasCondition( COND_NEW_ENEMY ) )
{
m_flJumpTime = 0.0f;
}
if ( ShouldJump() )
{
SetCondition( COND_ASW_ALIEN_CAN_JUMP );
}
else
{
ClearCondition( COND_ASW_ALIEN_CAN_JUMP );
}
BaseClass::PrescheduleThink();
}
void CASW_Alien_Jumper::InputDisableJump( inputdata_t &inputdata )
{
m_bDisableJump = true;
CapabilitiesRemove( bits_CAP_MOVE_JUMP );
}
void CASW_Alien_Jumper::InputEnableJump( inputdata_t &inputdata )
{
m_bDisableJump = false;
CapabilitiesAdd( bits_CAP_MOVE_JUMP );
}
bool CASW_Alien_Jumper::IsJumping()
{
return IsCurSchedule(SCHED_ASW_ALIEN_JUMP);
}
// make this alien jump off the head of the ent he's standing on
bool CASW_Alien_Jumper::DoJumpOffHead()
{
//Too soon to try to jump
if ( m_flJumpTime > gpGlobals->curtime )
return false;
if (!(GetGroundEntity()) || GetNavType() == NAV_JUMP )
return false;
// force this drone to have jumping capabilities
m_bDisableJump = false;
CapabilitiesAdd( bits_CAP_MOVE_JUMP );
//Vector vecDest = RandomVector(-1, 1);
//vecDest.z = 0;
//vecDest *= random->RandomFloat(30, 100);
Vector vecDest;
AngleVectors(GetAbsAngles(), &vecDest);
vecDest *= 200.0f;
vecDest += GetAbsOrigin();
// Try the jump
AIMoveTrace_t moveTrace;
GetMoveProbe()->MoveLimit( NAV_JUMP, GetAbsOrigin(), vecDest, MASK_NPCSOLID, NULL, &moveTrace );
//See if it succeeded
if ( IsMoveBlocked( moveTrace.fStatus ) )
{
if ( asw_debug_aliens.GetInt() == 2 )
{
NDebugOverlay::Box( vecDest, GetHullMins(), GetHullMaxs(), 255, 0, 0, 0, 5 );
NDebugOverlay::Line( GetAbsOrigin(), vecDest, 255, 0, 0, 0, 5 );
}
m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f );
return false;
}
if ( asw_debug_aliens.GetInt() == 2 )
{
NDebugOverlay::Box( vecDest, GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 5 );
NDebugOverlay::Line( GetAbsOrigin(), vecDest, 0, 255, 0, 0, 5 );
}
//Save this jump in case the next time fails
m_vecSavedJump = moveTrace.vJumpVelocity;
m_vecLastJumpAttempt = vecDest;
SetSchedule(SCHED_ASW_ALIEN_JUMP);
m_bForcedStuckJump = true;
return true;
}
bool CASW_Alien_Jumper::DoJumpTo(Vector &vecDest)
{
//Too soon to try to jump
if ( m_flJumpTime > gpGlobals->curtime )
return false;
// only jump if you're on the ground
if (!(GetFlags() & FL_ONGROUND) || GetNavType() == NAV_JUMP )
return false;
// Don't jump if I'm not allowed
if ( ( CapabilitiesGet() & bits_CAP_MOVE_JUMP ) == false )
return false;
// Try the jump
AIMoveTrace_t moveTrace;
GetMoveProbe()->MoveLimit( NAV_JUMP, GetAbsOrigin(), vecDest, MASK_NPCSOLID, NULL, &moveTrace );
//See if it succeeded
if ( IsMoveBlocked( moveTrace.fStatus ) )
{
if ( asw_debug_aliens.GetInt() == 2 )
{
NDebugOverlay::Box( vecDest, GetHullMins(), GetHullMaxs(), 255, 0, 0, 0, 5 );
NDebugOverlay::Line( GetAbsOrigin(), vecDest, 255, 0, 0, 0, 5 );
}
m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f );
return false;
}
if ( asw_debug_aliens.GetInt() == 2 )
{
NDebugOverlay::Box( vecDest, GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 5 );
NDebugOverlay::Line( GetAbsOrigin(), vecDest, 0, 255, 0, 0, 5 );
}
//Save this jump in case the next time fails
m_vecSavedJump = moveTrace.vJumpVelocity;
m_vecLastJumpAttempt = vecDest;
SetSchedule(SCHED_ASW_ALIEN_JUMP);
m_bForcedStuckJump = true;
//Msg("Drone saving jump vec %f %f %f\n", m_vecSavedJump.x, m_vecSavedJump.y, m_vecSavedJump.z);
return true;
}
bool CASW_Alien_Jumper::DoForcedJump( Vector &vecVelocity )
{
//Too soon to try to jump
if ( m_flJumpTime > gpGlobals->curtime )
return false;
// only jump if you're on the ground
if (!(GetFlags() & FL_ONGROUND) || GetNavType() == NAV_JUMP )
return false;
// Don't jump if I'm not allowed
if ( ( CapabilitiesGet() & bits_CAP_MOVE_JUMP ) == false )
return false;
m_vecSavedJump = vecVelocity;
m_vecLastJumpAttempt = GetAbsOrigin() + vecVelocity * 100;
SetSchedule(SCHED_ASW_ALIEN_JUMP);
m_bForcedStuckJump = true;
return true;
}
void CASW_Alien_Jumper::WaitAndRetryJump(Vector &vecDest)
{
m_vecLastJumpAttempt = vecDest;
SetSchedule(SCHED_ASW_WAIT_AND_RETRY_JUMP);
}
AI_BEGIN_CUSTOM_NPC( asw_alien_jumper, CASW_Alien_Jumper )
//Conditions
DECLARE_CONDITION( COND_ASW_ALIEN_CAN_JUMP )
//Squad slots
DECLARE_SQUADSLOT( SQUAD_SLOT_ALIEN_JUMP )
//Tasks
DECLARE_TASK( TASK_ASW_ALIEN_JUMP )
DECLARE_TASK( TASK_ASW_ALIEN_FACE_JUMP )
DECLARE_TASK( TASK_ASW_ALIEN_RETRY_JUMP )
//Activities
DECLARE_ACTIVITY( ACT_ASW_ALIEN_JUMP_START )
DECLARE_ACTIVITY( ACT_ASW_ALIEN_LAND )
//Events
DECLARE_ANIMEVENT( AE_ASW_ALIEN_START_JUMP )
DECLARE_ANIMEVENT( AE_ASW_ALIEN_GLIDE )
//Schedules
//==================================================
// Jump
//==================================================
DEFINE_SCHEDULE
(
SCHED_ASW_ALIEN_JUMP,
" Tasks"
" TASK_STOP_MOVING 0"
" TASK_ASW_ALIEN_FACE_JUMP 0"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_ASW_ALIEN_JUMP_START"
" TASK_ASW_ALIEN_JUMP 0"
""
" Interrupts"
" COND_TASK_FAILED"
)
DEFINE_SCHEDULE
(
SCHED_ASW_WAIT_AND_RETRY_JUMP,
" Tasks"
" TASK_STOP_MOVING 0"
" TASK_WAIT_RANDOM 1"
" TASK_ASW_ALIEN_RETRY_JUMP 0"
""
" Interrupts"
" COND_TASK_FAILED"
)
AI_END_CUSTOM_NPC()