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

📄 hl1_npc_tentacle.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//=========== (C) Copyright 2000 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: Bullseyes act as targets for other NPC's to attack and to trigger
//			events 
//
// $Workfile:     $
// $Date:         $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================

#include	"cbase.h"
#include	"AI_Default.h"
#include	"AI_Task.h"
#include	"AI_Schedule.h"
#include	"AI_Node.h"
#include	"AI_Hull.h"
#include	"AI_Hint.h"
#include	"AI_Route.h"
#include	"AI_Senses.h"
#include	"AI_Motor.h"
#include	"soundent.h"
#include	"game.h"
#include	"NPCEvent.h"
#include	"EntityList.h"
#include	"activitylist.h"
#include	"animation.h"
#include	"basecombatweapon.h"
#include	"IEffects.h"
#include	"vstdlib/random.h"
#include	"engine/IEngineSound.h"
#include	"ammodef.h"
#include	"hl1_ai_basenpc.h"
#include	"studio.h"			//hitbox parsing
#include	"collisionutils.h"	//ComputeSeparatingPlane

#include	"physics_bone_follower.h"	//For BoneFollowerManager

#define ACT_T_IDLE		1010
Activity ACT_1010;
Activity ACT_1011;
Activity ACT_1012;
Activity ACT_1013;

#define ACT_T_TAP		1020
Activity ACT_1020;
Activity ACT_1021;
Activity ACT_1022;
Activity ACT_1023;

#define ACT_T_STRIKE	1030
Activity ACT_1030;
Activity ACT_1031;
Activity ACT_1032;
Activity ACT_1033;

#define ACT_T_REARIDLE	1040
Activity ACT_1040;
Activity ACT_1041;
Activity ACT_1042;
Activity ACT_1043;
Activity ACT_1044;

class CNPC_Tentacle : public CHL1BaseNPC
{
	DECLARE_CLASS( CNPC_Tentacle, CHL1BaseNPC );
public:

	CNPC_Tentacle();

	void Spawn( );
	void Precache( );
	bool KeyValue( const char *szKeyName, const char *szValue );

	int Level( float dz );
	int MyLevel( void );
	float MyHeight( void );

	// Don't allow the tentacle to go across transitions!!!
	virtual int	ObjectCaps( void ) { return CAI_BaseNPC::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }

	void Start ( void );
	void Cycle ( void );
	void HitTouch( CBaseEntity *pOther );

	void SetObjectCollisionBox( void )
	{
		SetAbsMins( GetAbsOrigin() + Vector(-400, -400, 0) );
		SetAbsMaxs( GetAbsOrigin() + Vector(400, 400, 850) );
	}

	void HandleAnimEvent( animevent_t *pEvent );
	float HearingSensitivity( void ) { return 2.0; };

	virtual int OnTakeDamage( const CTakeDamageInfo &info );

	bool CreateVPhysics( void );

	void UpdateOnRemove( void );

	float m_flInitialYaw;
	int m_iGoalAnim;
	int m_iLevel;
	int m_iDir;
	float m_flFramerateAdj;
	float m_flSoundYaw;
	int m_iSoundLevel;
	float m_flSoundTime;
	float m_flSoundRadius;
	int m_iHitDmg;
	float m_flHitTime;

	float m_flTapRadius;

	float m_flNextSong;
	static int g_fFlySound;
	static int g_fSquirmSound;

	float m_flMaxYaw;
	int m_iTapSound;

	Vector m_vecPrevSound;
	float m_flPrevSoundTime;

	static const char *pHitSilo[];
	static const char *pHitDirt[];
	static const char *pHitWater[];

	float	MaxYawSpeed( void ) { 	return 18.0f;	}

	bool	HeardAnything( void );

	Class_T Classify ( void );
	
	CBoneFollowerManager	m_BoneFollowerManager;

	DECLARE_DATADESC();
	DEFINE_CUSTOM_AI;
};

// Crane bones that have physics followers
static const char *pTentacleFollowerBoneNames[] =
{
	"Bone08",
	"Bone09"
};

int CNPC_Tentacle :: g_fFlySound;
int CNPC_Tentacle :: g_fSquirmSound;

LINK_ENTITY_TO_CLASS( monster_tentacle, CNPC_Tentacle );

// stike sounds
#define TE_NONE -1
#define TE_SILO 0
#define TE_DIRT 1
#define TE_WATER 2

const char *CNPC_Tentacle::pHitSilo[] = 
{
	"tentacle/te_strike1.wav",
	"tentacle/te_strike2.wav",
};

const char *CNPC_Tentacle::pHitDirt[] = 
{
	"player/pl_dirt1.wav",
	"player/pl_dirt2.wav",
	"player/pl_dirt3.wav",
	"player/pl_dirt4.wav",
};

const char *CNPC_Tentacle::pHitWater[] = 
{
	"player/pl_slosh1.wav",
	"player/pl_slosh2.wav",
	"player/pl_slosh3.wav",
	"player/pl_slosh4.wav",
};

// animation sequence aliases 
typedef enum
{
	TENTACLE_ANIM_Pit_Idle,

	TENTACLE_ANIM_rise_to_Temp1,
	TENTACLE_ANIM_Temp1_to_Floor,
	TENTACLE_ANIM_Floor_Idle,
	TENTACLE_ANIM_Floor_Fidget_Pissed,
	TENTACLE_ANIM_Floor_Fidget_SmallRise,
	TENTACLE_ANIM_Floor_Fidget_Wave,
	TENTACLE_ANIM_Floor_Strike,
	TENTACLE_ANIM_Floor_Tap,
	TENTACLE_ANIM_Floor_Rotate,
	TENTACLE_ANIM_Floor_Rear,
	TENTACLE_ANIM_Floor_Rear_Idle,
	TENTACLE_ANIM_Floor_to_Lev1,

	TENTACLE_ANIM_Lev1_Idle,
	TENTACLE_ANIM_Lev1_Fidget_Claw,
	TENTACLE_ANIM_Lev1_Fidget_Shake,
	TENTACLE_ANIM_Lev1_Fidget_Snap,
	TENTACLE_ANIM_Lev1_Strike,
	TENTACLE_ANIM_Lev1_Tap,
	TENTACLE_ANIM_Lev1_Rotate,
	TENTACLE_ANIM_Lev1_Rear,
	TENTACLE_ANIM_Lev1_Rear_Idle,
	TENTACLE_ANIM_Lev1_to_Lev2,

	TENTACLE_ANIM_Lev2_Idle,
	TENTACLE_ANIM_Lev2_Fidget_Shake,
	TENTACLE_ANIM_Lev2_Fidget_Swing,
	TENTACLE_ANIM_Lev2_Fidget_Tut,
	TENTACLE_ANIM_Lev2_Strike,
	TENTACLE_ANIM_Lev2_Tap,
	TENTACLE_ANIM_Lev2_Rotate,
	TENTACLE_ANIM_Lev2_Rear,
	TENTACLE_ANIM_Lev2_Rear_Idle,
	TENTACLE_ANIM_Lev2_to_Lev3,

	TENTACLE_ANIM_Lev3_Idle,
	TENTACLE_ANIM_Lev3_Fidget_Shake,
	TENTACLE_ANIM_Lev3_Fidget_Side,
	TENTACLE_ANIM_Lev3_Fidget_Swipe,
	TENTACLE_ANIM_Lev3_Strike,
	TENTACLE_ANIM_Lev3_Tap,
	TENTACLE_ANIM_Lev3_Rotate,
	TENTACLE_ANIM_Lev3_Rear,
	TENTACLE_ANIM_Lev3_Rear_Idle,

	TENTACLE_ANIM_Lev1_Door_reach,

	TENTACLE_ANIM_Lev3_to_Engine,
	TENTACLE_ANIM_Engine_Idle,
	TENTACLE_ANIM_Engine_Sway,
	TENTACLE_ANIM_Engine_Swat,
	TENTACLE_ANIM_Engine_Bob,
	TENTACLE_ANIM_Engine_Death1,
	TENTACLE_ANIM_Engine_Death2,
	TENTACLE_ANIM_Engine_Death3,

	TENTACLE_ANIM_none
} TENTACLE_ANIM;

BEGIN_DATADESC( CNPC_Tentacle )
	DEFINE_FIELD( CNPC_Tentacle, m_flInitialYaw, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Tentacle, m_iGoalAnim, FIELD_INTEGER ),
	DEFINE_FIELD( CNPC_Tentacle, m_iLevel, FIELD_INTEGER ),
	DEFINE_FIELD( CNPC_Tentacle, m_iDir, FIELD_INTEGER ),
	DEFINE_FIELD( CNPC_Tentacle, m_flFramerateAdj, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Tentacle, m_flSoundYaw, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Tentacle, m_iSoundLevel, FIELD_INTEGER ),
	DEFINE_FIELD( CNPC_Tentacle, m_flSoundTime, FIELD_TIME ),
	DEFINE_FIELD( CNPC_Tentacle, m_flSoundRadius, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Tentacle, m_iHitDmg, FIELD_INTEGER ),
	DEFINE_FIELD( CNPC_Tentacle, m_flHitTime, FIELD_TIME ),
	DEFINE_FIELD( CNPC_Tentacle, m_flTapRadius, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Tentacle, m_flNextSong, FIELD_TIME ),
	DEFINE_FIELD( CNPC_Tentacle, m_iTapSound, FIELD_INTEGER ),
	DEFINE_FIELD( CNPC_Tentacle, m_flMaxYaw, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Tentacle, m_vecPrevSound, FIELD_POSITION_VECTOR ),
	DEFINE_FIELD( CNPC_Tentacle, m_flPrevSoundTime, FIELD_TIME ),
	DEFINE_THINKFUNC( CNPC_Tentacle, Start ),
	DEFINE_THINKFUNC( CNPC_Tentacle, Cycle ),
	DEFINE_ENTITYFUNC( CNPC_Tentacle, HitTouch ),
END_DATADESC()

Class_T CNPC_Tentacle::Classify ( void ) 
{ 
	return CLASS_ALIEN_MONSTER;	
}


CNPC_Tentacle::CNPC_Tentacle()
{
	m_flMaxYaw = 65;
	m_iTapSound = 0;
}

bool CNPC_Tentacle::KeyValue( const char *szKeyName, const char *szValue  )
{
	if ( FStrEq( szKeyName, "sweeparc") )
	{
		 m_flMaxYaw = atof( szValue ) / 2.0;
		 return true;
	}
	else if (FStrEq( szKeyName, "sound"))
	{
		 m_iTapSound = atoi( szValue );
		 return true;
	}
	else
		return BaseClass::KeyValue( szKeyName, szValue );

	return false;
}

//
// Tentacle Spawn
//
void CNPC_Tentacle::Spawn( )
{
	Precache( );

	SetSolid( SOLID_BBOX );

	//Necessary for TestCollision to be called for hitbox ray hits
	AddSolidFlags( FSOLID_CUSTOMRAYTEST );

	SetMoveType( MOVETYPE_FLY );
	m_fEffects			= 0;
	m_iHealth			= 75;
	SetSequence( 0 );

	SetModel( "models/tentacle2.mdl" );
	UTIL_SetSize( this, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );

	m_takedamage		= DAMAGE_AIM;
	AddFlag( FL_NPC );
	
	m_bloodColor		= BLOOD_COLOR_GREEN;

	ResetSequenceInfo( );
	m_iDir = 1;

	SetThink( Start );
	SetNextThink( gpGlobals->curtime + 0.2 );

	SetTouch( HitTouch );

	m_flInitialYaw = GetAbsAngles().y;
	GetMotor()->SetIdealYawAndUpdate( m_flInitialYaw );
	
	g_fFlySound = FALSE;
	g_fSquirmSound = FALSE;

	m_iHitDmg = 200;

	if (m_flMaxYaw <= 0)
		m_flMaxYaw = 65;

	m_NPCState = NPC_STATE_IDLE;

	UTIL_SetOrigin( this, GetAbsOrigin() );

	CreateVPhysics();
}

void CNPC_Tentacle::UpdateOnRemove( void )
{
	m_BoneFollowerManager.DestroyBoneFollowers();
	BaseClass::UpdateOnRemove();
}

void CNPC_Tentacle::Precache( )
{
	engine->PrecacheModel("models/tentacle2.mdl");

	enginesound->PrecacheSound("ambience/flies.wav");
	enginesound->PrecacheSound("ambience/squirm2.wav");

	enginesound->PrecacheSound("tentacle/te_alert1.wav");
	enginesound->PrecacheSound("tentacle/te_alert2.wav");
	enginesound->PrecacheSound("tentacle/te_flies1.wav");
	enginesound->PrecacheSound("tentacle/te_move1.wav");
	enginesound->PrecacheSound("tentacle/te_move2.wav");
	enginesound->PrecacheSound("tentacle/te_roar1.wav");
	enginesound->PrecacheSound("tentacle/te_roar2.wav");
	enginesound->PrecacheSound("tentacle/te_search1.wav");
	enginesound->PrecacheSound("tentacle/te_search2.wav");
	enginesound->PrecacheSound("tentacle/te_sing1.wav");
	enginesound->PrecacheSound("tentacle/te_sing2.wav");
	enginesound->PrecacheSound("tentacle/te_squirm2.wav");
	enginesound->PrecacheSound("tentacle/te_strike1.wav");
	enginesound->PrecacheSound("tentacle/te_strike2.wav");
	enginesound->PrecacheSound("tentacle/te_swing1.wav");
	enginesound->PrecacheSound("tentacle/te_swing2.wav");

	PRECACHE_SOUND_ARRAY( pHitSilo );
	PRECACHE_SOUND_ARRAY( pHitDirt );
	PRECACHE_SOUND_ARRAY( pHitWater );
	
	BaseClass::Precache();
}


int CNPC_Tentacle::Level( float dz )
{
	if (dz < 216)
		return 0;
	if (dz < 408)
		return 1;
	if (dz < 600)
		return 2;
	return 3;
}


float CNPC_Tentacle::MyHeight( )
{
	switch ( MyLevel( ) )
	{
	case 1:
		return 256;
	case 2:
		return 448;
	case 3:
		return 640;
	}
	return 0;
}


int CNPC_Tentacle::MyLevel( )
{
	switch( GetSequence() )
	{
	case TENTACLE_ANIM_Pit_Idle: 
		return -1;

	case TENTACLE_ANIM_rise_to_Temp1:
	case TENTACLE_ANIM_Temp1_to_Floor:
	case TENTACLE_ANIM_Floor_to_Lev1:
		return 0;

	case TENTACLE_ANIM_Floor_Idle:
	case TENTACLE_ANIM_Floor_Fidget_Pissed:
	case TENTACLE_ANIM_Floor_Fidget_SmallRise:
	case TENTACLE_ANIM_Floor_Fidget_Wave:
	case TENTACLE_ANIM_Floor_Strike:
	case TENTACLE_ANIM_Floor_Tap:
	case TENTACLE_ANIM_Floor_Rotate:
	case TENTACLE_ANIM_Floor_Rear:
	case TENTACLE_ANIM_Floor_Rear_Idle:
		return 0;

	case TENTACLE_ANIM_Lev1_Idle:
	case TENTACLE_ANIM_Lev1_Fidget_Claw:
	case TENTACLE_ANIM_Lev1_Fidget_Shake:
	case TENTACLE_ANIM_Lev1_Fidget_Snap:
	case TENTACLE_ANIM_Lev1_Strike:
	case TENTACLE_ANIM_Lev1_Tap:
	case TENTACLE_ANIM_Lev1_Rotate:
	case TENTACLE_ANIM_Lev1_Rear:
	case TENTACLE_ANIM_Lev1_Rear_Idle:
		return 1;

	case TENTACLE_ANIM_Lev1_to_Lev2:
		return 1;

	case TENTACLE_ANIM_Lev2_Idle:
	case TENTACLE_ANIM_Lev2_Fidget_Shake:
	case TENTACLE_ANIM_Lev2_Fidget_Swing:
	case TENTACLE_ANIM_Lev2_Fidget_Tut:
	case TENTACLE_ANIM_Lev2_Strike:
	case TENTACLE_ANIM_Lev2_Tap:
	case TENTACLE_ANIM_Lev2_Rotate:
	case TENTACLE_ANIM_Lev2_Rear:
	case TENTACLE_ANIM_Lev2_Rear_Idle:
		return 2;

	case TENTACLE_ANIM_Lev2_to_Lev3:
		return 2;

	case TENTACLE_ANIM_Lev3_Idle:
	case TENTACLE_ANIM_Lev3_Fidget_Shake:
	case TENTACLE_ANIM_Lev3_Fidget_Side:
	case TENTACLE_ANIM_Lev3_Fidget_Swipe:
	case TENTACLE_ANIM_Lev3_Strike:
	case TENTACLE_ANIM_Lev3_Tap:
	case TENTACLE_ANIM_Lev3_Rotate:
	case TENTACLE_ANIM_Lev3_Rear:
	case TENTACLE_ANIM_Lev3_Rear_Idle:
		return 3;

	case TENTACLE_ANIM_Lev1_Door_reach:
		return -1;
	}
	return -1;
}

void CNPC_Tentacle::Start( void )
{
	SetThink( Cycle );

	CPASAttenuationFilter filter( this );

	if ( !g_fFlySound )
	{
		enginesound->EmitSound( filter, entindex(), CHAN_BODY, "ambience/flies.wav", 1, ATTN_NORM );
		g_fFlySound = TRUE;
	}
	else if ( !g_fSquirmSound )
	{
		enginesound->EmitSound( filter, entindex(), CHAN_BODY, "ambience/squirm2.wav", 1, ATTN_NORM );
		g_fSquirmSound = TRUE;
	}
	
	SetNextThink( gpGlobals->curtime + 0.1 );
}

bool CNPC_Tentacle::HeardAnything( void )
{
	if ( HasCondition( COND_HEAR_DANGER ) ||
		 HasCondition( COND_HEAR_THUMPER ) ||
		 HasCondition( COND_HEAR_BUGBAIT ) ||
		 HasCondition( COND_HEAR_COMBAT ) ||
		 HasCondition( COND_HEAR_WORLD ) ||
		 HasCondition( COND_HEAR_PLAYER ) ||
		 HasCondition( COND_HEAR_BULLET_IMPACT ) ||
		 HasCondition( COND_HEAR_PHYSICS_DANGER ) )
		 return true;

	return false;
}

void CNPC_Tentacle::Cycle( void )
{
	// ALERT( at_console, "%s %.2f %d %d\n", STRING( pev->targetname ), pev->origin.z, m_MonsterState, m_IdealMonsterState );
	SetNextThink( gpGlobals->curtime + 0.1 );

	// ALERT( at_console, "%s %d %d %d %f %f\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim, m_iDir, pev->framerate, pev->health );

	if ( m_NPCState == NPC_STATE_SCRIPT || m_IdealNPCState == NPC_STATE_SCRIPT)
	{
		SetAbsAngles( QAngle( GetAbsAngles().x, m_flInitialYaw, GetAbsAngles().z ) );
		GetMotor()->SetIdealYaw( m_flInitialYaw );	
		RemoveIgnoredConditions();
		NPCThink( );
		m_iGoalAnim = TENTACLE_ANIM_Pit_Idle;
		return;
	}
	
	StudioFrameAdvance();
	DispatchAnimEvents( this );

⌨️ 快捷键说明

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