⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 npc_sscanner.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. ===========
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Purpose: 
//
// $Workfile:     $
// $Date:         $
// $NoKeywords: $
//=============================================================================

#include "cbase.h"
#include "npc_sscanner.h"
#include "AI_Default.h"
#include "AI_Hull.h"
#include "AI_Hint.h"
#include "AI_Node.h" // just for GetFloorZ()
#include "AI_Navigator.h"
#include "ai_moveprobe.h"
#include "AI_Squad.h"
#include "explode.h"
#include "grenade_energy.h"
#include "ndebugoverlay.h"
#include "scanner_shield.h"
#include "npc_sscanner_beam.h"
#include "gib.h"
#include "IEffects.h"
#include "vstdlib/random.h"
#include "engine/IEngineSound.h"
#include "movevars_shared.h"

#define	SSCANNER_MAX_SPEED				400
#define	SSCANNER_NUM_GLOWS				2
#define SSCANNER_GIB_COUNT			5   
#define SSCANNER_ATTACK_NEAR_DIST		600
#define SSCANNER_ATTACK_FAR_DIST		800

#define SSCANNER_COVER_NEAR_DIST		60
#define SSCANNER_COVER_FAR_DIST		250
#define SSCANNER_MAX_SHEILD_DIST		400

#define	SSCANNER_BANK_RATE			5
#define SSCANNER_ENERGY_WARMUP_TIME	0.5
#define SSCANNER_MIN_GROUND_DIST		150

#define SSCANNER_GIB_COUNT			5 

ConVar	sk_sscanner_health( "sk_sscanner_health","0");

extern float	GetFloorZ(const Vector &origin, float fMaxDrop);

//-----------------------------------------------------------------------------
// Private activities.
//-----------------------------------------------------------------------------
int	ACT_SSCANNER_FLINCH_BACK;
int	ACT_SSCANNER_FLINCH_FRONT;
int	ACT_SSCANNER_FLINCH_LEFT;
int	ACT_SSCANNER_FLINCH_RIGHT;
int	ACT_SSCANNER_LOOK;
int	ACT_SSCANNER_OPEN;
int	ACT_SSCANNER_CLOSE;

//-----------------------------------------------------------------------------
// SScanner schedules.
//-----------------------------------------------------------------------------
enum SScannerSchedules
{
	SCHED_SSCANNER_HOVER = LAST_SHARED_SCHEDULE,
	SCHED_SSCANNER_PATROL,
	SCHED_SSCANNER_CHASE_ENEMY,
	SCHED_SSCANNER_CHASE_TARGET,
	SCHED_SSCANNER_OPEN,
	SCHED_SSCANNER_CLOSE,
};

//-----------------------------------------------------------------------------
// Custom tasks.
//-----------------------------------------------------------------------------
enum SScannerTasks
{
	TASK_SSCANNER_OPEN = LAST_SHARED_TASK,
	TASK_SSCANNER_CLOSE,
};

//-----------------------------------------------------------------------------
// Custom Conditions
//-----------------------------------------------------------------------------
enum SScanner_Conds
{
	COND_SSCANNER_FLY_BLOCKED	= LAST_SHARED_CONDITION,
	COND_SSCANNER_FLY_CLEAR,
	COND_SSCANNER_PISSED_OFF,
};


BEGIN_DATADESC( CNPC_SScanner )

	DEFINE_FIELD( CNPC_SScanner,	m_lastHurtTime,				FIELD_FLOAT ),

	DEFINE_FIELD( CNPC_SScanner,	m_nState,					FIELD_INTEGER),
	DEFINE_FIELD( CNPC_SScanner,	m_bShieldsDisabled,			FIELD_BOOLEAN),
	DEFINE_FIELD( CNPC_SScanner,	m_pShield,					FIELD_CLASSPTR ),
	DEFINE_FIELD( CNPC_SScanner,	m_pShieldBeamL,				FIELD_CLASSPTR ),
	DEFINE_FIELD( CNPC_SScanner,	m_pShieldBeamR,				FIELD_CLASSPTR ),
	DEFINE_FIELD( CNPC_SScanner,	m_fNextShieldCheckTime,		FIELD_TIME),

	DEFINE_FIELD( CNPC_SScanner,	m_fNextFlySoundTime,		FIELD_TIME),

	DEFINE_FIELD( CNPC_SScanner,	m_vCoverPosition,			FIELD_POSITION_VECTOR),

END_DATADESC()


LINK_ENTITY_TO_CLASS( npc_sscanner, CNPC_SScanner );
IMPLEMENT_CUSTOM_AI( npc_sscanner, CNPC_SScanner );

CNPC_SScanner::CNPC_SScanner()
{
#ifdef _DEBUG
	m_vCurrentBanking.Init();
	m_vCoverPosition.Init();
#endif
}

//-----------------------------------------------------------------------------
// Purpose: Initialize the custom schedules
// Input  :
// Output :
//-----------------------------------------------------------------------------
void CNPC_SScanner::InitCustomSchedules(void) 
{
	INIT_CUSTOM_AI(CNPC_SScanner);

	ADD_CUSTOM_SCHEDULE(CNPC_SScanner,	SCHED_SSCANNER_HOVER);
	ADD_CUSTOM_SCHEDULE(CNPC_SScanner,	SCHED_SSCANNER_PATROL);
	ADD_CUSTOM_SCHEDULE(CNPC_SScanner,	SCHED_SSCANNER_CHASE_ENEMY);
	ADD_CUSTOM_SCHEDULE(CNPC_SScanner,	SCHED_SSCANNER_CHASE_TARGET);
	ADD_CUSTOM_SCHEDULE(CNPC_SScanner,	SCHED_SSCANNER_OPEN);
	ADD_CUSTOM_SCHEDULE(CNPC_SScanner,	SCHED_SSCANNER_CLOSE);

	ADD_CUSTOM_CONDITION(CNPC_SScanner,	COND_SSCANNER_FLY_BLOCKED);
	ADD_CUSTOM_CONDITION(CNPC_SScanner,	COND_SSCANNER_FLY_CLEAR);
	ADD_CUSTOM_CONDITION(CNPC_SScanner,	COND_SSCANNER_PISSED_OFF);

	ADD_CUSTOM_TASK(CNPC_SScanner,		TASK_SSCANNER_OPEN);
	ADD_CUSTOM_TASK(CNPC_SScanner,		TASK_SSCANNER_CLOSE);

	ADD_CUSTOM_ACTIVITY(CNPC_SScanner,	ACT_SSCANNER_FLINCH_BACK);
	ADD_CUSTOM_ACTIVITY(CNPC_SScanner,	ACT_SSCANNER_FLINCH_FRONT);
	ADD_CUSTOM_ACTIVITY(CNPC_SScanner,	ACT_SSCANNER_FLINCH_LEFT);
	ADD_CUSTOM_ACTIVITY(CNPC_SScanner,	ACT_SSCANNER_FLINCH_RIGHT);
	ADD_CUSTOM_ACTIVITY(CNPC_SScanner,	ACT_SSCANNER_OPEN);
	ADD_CUSTOM_ACTIVITY(CNPC_SScanner,	ACT_SSCANNER_CLOSE);

	AI_LOAD_SCHEDULE(CNPC_SScanner,	SCHED_SSCANNER_HOVER);
	AI_LOAD_SCHEDULE(CNPC_SScanner,	SCHED_SSCANNER_PATROL);
	AI_LOAD_SCHEDULE(CNPC_SScanner,	SCHED_SSCANNER_CHASE_ENEMY);
	AI_LOAD_SCHEDULE(CNPC_SScanner,	SCHED_SSCANNER_CHASE_TARGET);
	AI_LOAD_SCHEDULE(CNPC_SScanner,	SCHED_SSCANNER_OPEN);
	AI_LOAD_SCHEDULE(CNPC_SScanner,	SCHED_SSCANNER_CLOSE);
}

//-----------------------------------------------------------------------------
// Purpose: Indicates this NPC's place in the relationship table.
//-----------------------------------------------------------------------------
Class_T	CNPC_SScanner::Classify(void)
{
	return(CLASS_SCANNER);
}


//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPC_SScanner::StopLoopingSounds(void)
{
	StopSound( "NPC_SScanner.FlySound" );
	BaseClass::StopLoopingSounds();
}


//-----------------------------------------------------------------------------
// Purpose: 
// Input  : Type - 
// Output : int - new schedule type
//-----------------------------------------------------------------------------
int CNPC_SScanner::TranslateSchedule( int scheduleType ) 
{
	switch( scheduleType )
	{
	case SCHED_FAIL_TAKE_COVER:
		return SCHED_SSCANNER_PATROL;
		break;
	}
	return BaseClass::TranslateSchedule(scheduleType);
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPC_SScanner::Event_Killed( const CTakeDamageInfo &info )
{
	BaseClass::Event_Killed( info );
	StopShield();
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  :
// Output :
//-----------------------------------------------------------------------------
void CNPC_SScanner::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr )
{
	if ( info.GetDamageType() & DMG_BULLET)
	{
		g_pEffects->Ricochet(ptr->endpos,ptr->plane.normal);
	}

	BaseClass::TraceAttack( info, vecDir, ptr );
}


//------------------------------------------------------------------------------
// Purpose : Override to split in two when attacked
// Input   :
// Output  :
//------------------------------------------------------------------------------
int CNPC_SScanner::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo )
{
	CTakeDamageInfo info = inputInfo;

	// Don't take friendly fire from combine
	if (info.GetAttacker()->Classify() == CLASS_COMBINE)
	{
		info.SetDamage( 0 );
	}
	else if (m_nState == SSCANNER_OPEN)
	{
		// Flinch in the direction of the attack
		float vAttackYaw = VecToYaw(g_vecAttackDir);

		float vAngleDiff = UTIL_AngleDiff( vAttackYaw, m_fHeadYaw );

		if (vAngleDiff > -45 && vAngleDiff < 45)
		{
			SetActivity((Activity)ACT_SSCANNER_FLINCH_BACK);
		}
		else if (vAngleDiff < -45 && vAngleDiff > -135)
		{
			SetActivity((Activity)ACT_SSCANNER_FLINCH_LEFT);
		}
		else if (vAngleDiff >  45 && vAngleDiff <  135)
		{
			SetActivity((Activity)ACT_SSCANNER_FLINCH_RIGHT);
		}
		else
		{
			SetActivity((Activity)ACT_SSCANNER_FLINCH_FRONT);
		}

		m_lastHurtTime = gpGlobals->curtime;
	}
	return (BaseClass::OnTakeDamage_Alive( info ));
}

//------------------------------------------------------------------------------
// Purpose :
// Input   :
// Output  :
//------------------------------------------------------------------------------
bool CNPC_SScanner::IsValidShieldCover( Vector &vCoverPos )
{
	if (GetEnemy() == NULL)
	{
		return true;
	}

	// Make sure I can get here
	trace_t tr;
	AI_TraceEntity( this, GetAbsOrigin(), vCoverPos, MASK_NPCSOLID, &tr );
	if (tr.fraction != 1.0)
	{
		//NDebugOverlay::Cross3D(vCoverPos,Vector(-15,-15,-15),Vector(5,5,5),255,0,0,true,1.0);
		return false;
	}

	// Make sure position is in cover
	Vector vThreatEyePos = GetEnemy()->EyePosition();
	AI_TraceLine ( vCoverPos, vThreatEyePos, MASK_OPAQUE,  this, COLLISION_GROUP_NONE, &tr );
	if (tr.fraction == 1.0)
	{
		//NDebugOverlay::Cross3D(vCoverPos,Vector(-15,-15,-15),Vector(5,5,5),0,0,255,true,1.0);
		return false;
	}
	else
	{
		//NDebugOverlay::Cross3D(vCoverPos,Vector(-15,-15,-15),Vector(5,5,5),0,255,0,true,1.0);
		return true;
	}
}

//------------------------------------------------------------------------------
// Purpose : Attempts to find a position that is in cover from the enemy
//			 but with in range to use shield.
// Input   :
// Output  : True if a cover position was set
//------------------------------------------------------------------------------
bool CNPC_SScanner::SetShieldCoverPosition( void )
{
	// Make sure I'm shielding someone and have an enemy
	if (GetTarget() == NULL	||
		GetEnemy()	 == NULL	)
	{
		m_vCoverPosition = vec3_origin;
		return false;
	}

	// If I have a current cover position check if it's valid
	if (m_vCoverPosition != vec3_origin)
	{
		// If in range of my shield target, and valid cover keep same cover position
		if ((m_vCoverPosition - GetTarget()->GetLocalOrigin()).Length() < SSCANNER_COVER_FAR_DIST &&
			IsValidShieldCover(m_vCoverPosition)								)
		{
			return true;
		}
	}

	// Otherwise try a random direction
	QAngle vAngle	= QAngle(0,random->RandomInt(-180,180),0);
	Vector vForward;
	AngleVectors( vAngle, &vForward );
	
	// Now get the position
	Vector vTestPos = GetTarget()->GetLocalOrigin() + vForward * (random->RandomInt(150,240)); 
	vTestPos.z		= GetLocalOrigin().z;

	// Is it a valid cover position
	if (IsValidShieldCover(vTestPos))
	{
		m_vCoverPosition = vTestPos;
		return true;
	}
	else
	{
		m_vCoverPosition = vec3_origin;
		return false;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Handles movement towards the last move target.
// Input  : flInterval - 
//-----------------------------------------------------------------------------
bool CNPC_SScanner::OverridePathMove( float flInterval )
{
	CBaseEntity *pMoveTarget = (GetTarget()) ? GetTarget() : GetEnemy();
	Vector waypointDir = GetNavigator()->GetCurWaypointPos() - GetLocalOrigin();
	VectorNormalize(waypointDir);

	// -----------------------------------------------------------------
	// Check route is blocked
	// ------------------------------------------------------------------
	Vector checkPos = GetLocalOrigin() + (waypointDir * (m_flSpeed * flInterval));

	AIMoveTrace_t moveTrace;
	GetMoveProbe()->MoveLimit( NAV_FLY, GetLocalOrigin(), checkPos, MASK_NPCSOLID|CONTENTS_WATER,
		pMoveTarget,&moveTrace);

	if (IsMoveBlocked( moveTrace ))
	{
		TaskFail(FAIL_NO_ROUTE);
		GetNavigator()->ClearGoal();
		return true;
	}
	
	// --------------------------------------------------
	//  Check if I've reached my goal
	// --------------------------------------------------
	
	Vector lastPatrolDir = GetNavigator()->GetCurWaypointPos() - GetLocalOrigin();
	
	
	if ( ProgressFlyPath( flInterval, pMoveTarget, MASK_NPCSOLID,
						  !IsCurSchedule( SCHED_SSCANNER_PATROL ) ) == AINPP_COMPLETE )
	{
		if (IsCurSchedule( SCHED_SSCANNER_PATROL ))
		{
			m_vLastPatrolDir = lastPatrolDir;
			VectorNormalize(m_vLastPatrolDir);
		}
		return true;
	}
	return false;
}

bool CNPC_SScanner::OverrideMove(float flInterval)
{
	// ----------------------------------------------
	//	Select move target 
	// ----------------------------------------------
	CBaseEntity*	pMoveTarget = NULL;
	float			fNearDist	= 0;
	float			fFarDist	= 0;
	if (GetTarget() != NULL )
	{
		pMoveTarget = GetTarget();
		fNearDist	= SSCANNER_COVER_NEAR_DIST;
		fFarDist	= SSCANNER_COVER_FAR_DIST;
	}
	else if (GetEnemy() != NULL )
	{
		pMoveTarget = GetEnemy();		
		fNearDist	= SSCANNER_ATTACK_NEAR_DIST;
		fFarDist	= SSCANNER_ATTACK_FAR_DIST;
	}

	// -----------------------------------------
	//  See if we can fly there directly
	// -----------------------------------------
	if (pMoveTarget)
	{
		trace_t tr;
		Vector endPos = GetAbsOrigin() + GetCurrentVelocity()*flInterval;
		AI_TraceHull(GetAbsOrigin(), pMoveTarget->GetAbsOrigin() + Vector(0,0,150),
			GetHullMins(), GetHullMaxs(), MASK_NPCSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
		if (tr.fraction != 1.0)
		{
			/*
			NDebugOverlay::Cross3D(GetLocalOrigin()+Vector(0,0,-60),Vector(-15,-15,-15),Vector(5,5,5),0,255,255,true,0.1);
			*/
			SetCondition( COND_SSCANNER_FLY_BLOCKED );
		}
		else
		{
			SetCondition( COND_SSCANNER_FLY_CLEAR );
		}
	}

	// -----------------------------------------------------------------
	// If I have a route, keep it updated and move toward target
	// ------------------------------------------------------------------
	if (GetNavigator()->IsGoalActive())
	{
		if ( OverridePathMove( flInterval ) )
			return true;
	}

	// ----------------------------------------------
	//	Move to target directly if path is clear
	// ----------------------------------------------
	else if ( pMoveTarget && HasCondition( COND_SSCANNER_FLY_CLEAR ) )
	{
		MoveToEntity(flInterval, pMoveTarget, fNearDist, fFarDist);
	}
	// -----------------------------------------------------------------
	// Otherwise just decelerate
	// -----------------------------------------------------------------
	else 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -