📄 hl1_npc_bigmomma.cpp
字号:
#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 "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 "AI_Navigator.h"
#include "decals.h"
#include "effect_dispatch_data.h"
#include "te_effect_dispatch.h"
#include "Sprite.h"
ConVar sk_bigmomma_health_factor( "sk_bigmomma_health_factor", "1" );
ConVar sk_bigmomma_dmg_slash( "sk_bigmomma_dmg_slash", "50" );
ConVar sk_bigmomma_dmg_blast( "sk_bigmomma_dmg_blast", "100" );
ConVar sk_bigmomma_radius_blast( "sk_bigmomma_radius_blast", "250" );
extern ConVar sv_gravity;
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
#define BIG_AE_STEP1 1 // Footstep left
#define BIG_AE_STEP2 2 // Footstep right
#define BIG_AE_STEP3 3 // Footstep back left
#define BIG_AE_STEP4 4 // Footstep back right
#define BIG_AE_SACK 5 // Sack slosh
#define BIG_AE_DEATHSOUND 6 // Death sound
#define BIG_AE_MELEE_ATTACKBR 8 // Leg attack
#define BIG_AE_MELEE_ATTACKBL 9 // Leg attack
#define BIG_AE_MELEE_ATTACK1 10 // Leg attack
#define BIG_AE_MORTAR_ATTACK1 11 // Launch a mortar
#define BIG_AE_LAY_CRAB 12 // Lay a headcrab
#define BIG_AE_JUMP_FORWARD 13 // Jump up and forward
#define BIG_AE_SCREAM 14 // alert sound
#define BIG_AE_PAIN_SOUND 15 // pain sound
#define BIG_AE_ATTACK_SOUND 16 // attack sound
#define BIG_AE_BIRTH_SOUND 17 // birth sound
#define BIG_AE_EARLY_TARGET 50 // Fire target early
enum
{
SCHED_NODE_FAIL = LAST_SHARED_SCHEDULE,
SCHED_BIG_NODE,
};
enum
{
TASK_MOVE_TO_NODE_RANGE = LAST_SHARED_TASK, // Move within node range
TASK_FIND_NODE, // Find my next node
TASK_PLAY_NODE_PRESEQUENCE, // Play node pre-script
TASK_PLAY_NODE_SEQUENCE, // Play node script
TASK_PROCESS_NODE, // Fire targets, etc.
TASK_WAIT_NODE, // Wait at the node
TASK_NODE_DELAY, // Delay walking toward node for a bit. You've failed to get there
TASK_NODE_YAW, // Get the best facing direction for this node
TASK_CHECK_NODE_PROXIMITY,
};
// User defined conditions
//#define bits_COND_NODE_SEQUENCE ( COND_SPECIAL1 ) // pev->netname contains the name of a sequence to play
// Attack distance constants
#define BIG_ATTACKDIST 170
#define BIG_MORTARDIST 800
#define BIG_MAXCHILDREN 6 // Max # of live headcrab children
#define bits_MEMORY_CHILDPAIR (bits_MEMORY_CUSTOM1)
#define bits_MEMORY_ADVANCE_NODE (bits_MEMORY_CUSTOM2)
#define bits_MEMORY_COMPLETED_NODE (bits_MEMORY_CUSTOM3)
#define bits_MEMORY_FIRED_NODE (bits_MEMORY_CUSTOM4)
int gSpitSprite, gSpitDebrisSprite;
Vector VecCheckSplatToss( CBaseEntity *pEntity, const Vector &vecSpot1, Vector vecSpot2, float maxHeight );
void MortarSpray( const Vector &position, const Vector &direction, int spriteModel, int count );
#define SF_INFOBM_RUN 0x0001
#define SF_INFOBM_WAIT 0x0002
//=========================================================
// Mortar shot entity
//=========================================================
class CBMortar : public CBaseAnimating
{
DECLARE_CLASS( CBMortar, CBaseAnimating );
public:
void Spawn( void );
static CBMortar *Shoot( CBaseEntity *pOwner, Vector vecStart, Vector vecVelocity );
void Touch( CBaseEntity *pOther );
void Animate( void );
float m_flDmgTime;
DECLARE_DATADESC();
int m_maxFrame;
int m_iFrame;
CSprite* pSprite;
};
LINK_ENTITY_TO_CLASS( bmortar, CBMortar );
BEGIN_DATADESC( CBMortar )
DEFINE_FIELD( CBMortar, m_maxFrame, FIELD_INTEGER ),
DEFINE_FIELD( CBMortar, m_flDmgTime, FIELD_FLOAT ),
DEFINE_FUNCTION( CBMortar, Animate ),
END_DATADESC()
// AI Nodes for Big Momma
class CInfoBM : public CPointEntity
{
DECLARE_CLASS( CInfoBM, CPointEntity );
public:
void Spawn( void );
bool KeyValue( const char *szKeyName, const char *szValue );
// name in pev->targetname
// next in pev->target
// radius in pev->scale
// health in pev->health
// Reach target in pev->message
// Reach delay in pev->speed
// Reach sequence in pev->netname
DECLARE_DATADESC();
int m_preSequence;
int m_curSequence;
float m_flRadius;
float m_flDelay;
string_t m_iszReachTarget;
string_t m_iszReachSequence;
string_t m_iszPreSequence;
const char *m_iszNameHack;
COutputEvent m_OnAnimationEvent;
};
LINK_ENTITY_TO_CLASS( info_bigmomma, CInfoBM );
BEGIN_DATADESC( CInfoBM )
DEFINE_FIELD( CInfoBM, m_flRadius, FIELD_FLOAT ),
DEFINE_FIELD( CInfoBM, m_flDelay, FIELD_FLOAT ),
DEFINE_KEYFIELD( CInfoBM, m_iszReachTarget, FIELD_STRING, "reachtarget" ),
DEFINE_KEYFIELD( CInfoBM, m_iszReachSequence, FIELD_STRING, "reachsequence" ),
DEFINE_KEYFIELD( CInfoBM, m_iszPreSequence, FIELD_STRING, "presequence" ),
DEFINE_OUTPUT( CInfoBM, m_OnAnimationEvent, "OnAnimationEvent" ),
END_DATADESC()
void CInfoBM::Spawn( void )
{
BaseClass::Spawn();
// Msg( "Name %s\n", STRING( GetEntityName() ) );
}
bool CInfoBM::KeyValue( const char *szKeyName, const char *szValue )
{
if (FStrEq( szKeyName, "radius"))
{
m_flRadius = atof( szValue );
return true;
}
else if (FStrEq( szKeyName, "reachdelay" ))
{
m_flDelay = atof( szValue);
return true;
}
else if (FStrEq( szKeyName, "health" ))
{
m_iHealth = atoi( szValue );
return true;
}
return BaseClass::KeyValue(szKeyName, szValue );
}
// UNDONE:
//
#define BIG_CHILDCLASS "monster_babycrab"
class CNPC_BigMomma : public CHL1BaseNPC
{
DECLARE_CLASS( CNPC_BigMomma, CHL1BaseNPC );
public:
void Spawn( void );
void Precache( void );
static const char *pChildDieSounds[];
static const char *pSackSounds[];
static const char *pDeathSounds[];
static const char *pAttackSounds[];
static const char *pAttackHitSounds[];
static const char *pBirthSounds[];
static const char *pAlertSounds[];
static const char *pPainSounds[];
static const char *pFootSounds[];
Class_T Classify( void ) { return CLASS_ALIEN_MONSTER; };
void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr );
int OnTakeDamage( const CTakeDamageInfo &info );
void HandleAnimEvent( animevent_t *pEvent );
void LayHeadcrab( void );
void LaunchMortar( void );
void DeathNotice( CBaseEntity *pevChild );
int MeleeAttack1Conditions( float flDot, float flDist ); // Slash
int MeleeAttack2Conditions( float flDot, float flDist ); // Lay a crab
int RangeAttack1Conditions( float flDot, float flDist ); // Mortar launch
BOOL CanLayCrab( void )
{
if ( m_crabTime < gpGlobals->curtime && m_crabCount < BIG_MAXCHILDREN )
{
// Don't spawn crabs inside each other
Vector mins = GetAbsOrigin() - Vector( 32, 32, 0 );
Vector maxs = GetAbsOrigin() + Vector( 32, 32, 0 );
CBaseEntity *pList[2];
int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_NPC );
for ( int i = 0; i < count; i++ )
{
if ( pList[i] != this ) // Don't hurt yourself!
return COND_NONE;
}
return COND_CAN_MELEE_ATTACK2;
}
return COND_NONE;
}
void Activate ( void );
void NodeReach( void );
void NodeStart( string_t iszNextNode );
bool ShouldGoToNode( void );
const char *GetNodeSequence( void )
{
CInfoBM *pTarget = (CInfoBM*)GetTarget();
if ( pTarget && FClassnameIs( pTarget, "info_bigmomma" ) )
{
return STRING( pTarget->m_iszReachSequence ); // netname holds node sequence
}
return NULL;
}
const char *GetNodePresequence( void )
{
CInfoBM *pTarget = (CInfoBM *)GetTarget();
if ( pTarget && FClassnameIs( pTarget, "info_bigmomma" ) )
{
return STRING( pTarget->m_iszPreSequence );
}
return NULL;
}
float GetNodeDelay( void )
{
CInfoBM *pTarget = (CInfoBM *)GetTarget();
if ( pTarget && FClassnameIs( pTarget, "info_bigmomma" ) )
{
return pTarget->m_flDelay; // Speed holds node delay
}
return 0;
}
float GetNodeRange( void )
{
CInfoBM *pTarget = (CInfoBM *)GetTarget();
if ( pTarget && FClassnameIs( pTarget, "info_bigmomma" ) )
{
return pTarget->m_flRadius; // Scale holds node delay
}
return 1e6;
}
float GetNodeYaw( void )
{
CBaseEntity *pTarget = GetTarget();
if ( pTarget )
{
if ( pTarget->GetAbsAngles().y != 0 )
return pTarget->GetAbsAngles().y;
}
return GetAbsAngles().y;
}
// Restart the crab count on each new level
void OnRestore( void )
{
BaseClass::OnRestore();
m_crabCount = 0;
}
virtual void SetObjectCollisionBox( void )
{
SetAbsMins( GetAbsOrigin() + Vector( -95, -95, 0 ) );
SetAbsMaxs( GetAbsOrigin() + Vector( 95, 95, 190 ) );
}
int SelectSchedule( void );
void StartTask( const Task_t *pTask );
void RunTask( const Task_t *pTask );
float MaxYawSpeed( void );
DECLARE_DATADESC();
DEFINE_CUSTOM_AI;
/* int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
void RunTask( Task_t *pTask );
void StartTask( Task_t *pTask );
Schedule_t *GetSchedule( void );
Schedule_t *GetScheduleOfType( int Type );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
void SetYawSpeed( void );
CUSTOM_SCHEDULES;
*/
private:
float m_nodeTime;
float m_crabTime;
float m_mortarTime;
float m_painSoundTime;
int m_crabCount;
float m_flDmgTime;
bool m_bDoneWithPath;
string_t m_iszTarget;
string_t m_iszNetName;
float m_flWait;
Vector m_vTossDir;
};
BEGIN_DATADESC( CNPC_BigMomma )
DEFINE_FIELD( CNPC_BigMomma, m_nodeTime, FIELD_TIME ),
DEFINE_FIELD( CNPC_BigMomma, m_crabTime, FIELD_TIME ),
DEFINE_FIELD( CNPC_BigMomma, m_mortarTime, FIELD_TIME ),
DEFINE_FIELD( CNPC_BigMomma, m_painSoundTime, FIELD_TIME ),
DEFINE_KEYFIELD( CNPC_BigMomma, m_iszNetName, FIELD_STRING, "netname" ),
DEFINE_FIELD( CNPC_BigMomma, m_flWait, FIELD_TIME ),
DEFINE_FIELD( CNPC_BigMomma, m_iszTarget, FIELD_STRING ),
END_DATADESC()
LINK_ENTITY_TO_CLASS ( monster_bigmomma, CNPC_BigMomma );
const char *CNPC_BigMomma::pChildDieSounds[] =
{
"gonarch/gon_childdie1.wav",
"gonarch/gon_childdie2.wav",
"gonarch/gon_childdie3.wav",
};
const char *CNPC_BigMomma::pSackSounds[] =
{
"gonarch/gon_sack1.wav",
"gonarch/gon_sack2.wav",
"gonarch/gon_sack3.wav",
};
const char *CNPC_BigMomma::pDeathSounds[] =
{
"gonarch/gon_die1.wav",
};
const char *CNPC_BigMomma::pAttackSounds[] =
{
"gonarch/gon_attack1.wav",
"gonarch/gon_attack2.wav",
"gonarch/gon_attack3.wav",
};
const char *CNPC_BigMomma::pAttackHitSounds[] =
{
"zombie/claw_strike1.wav",
"zombie/claw_strike2.wav",
"zombie/claw_strike3.wav",
};
const char *CNPC_BigMomma::pBirthSounds[] =
{
"gonarch/gon_birth1.wav",
"gonarch/gon_birth2.wav",
"gonarch/gon_birth3.wav",
};
const char *CNPC_BigMomma::pAlertSounds[] =
{
"gonarch/gon_alert1.wav",
"gonarch/gon_alert2.wav",
"gonarch/gon_alert3.wav",
};
const char *CNPC_BigMomma::pPainSounds[] =
{
"gonarch/gon_pain2.wav",
"gonarch/gon_pain4.wav",
"gonarch/gon_pain5.wav",
};
const char *CNPC_BigMomma::pFootSounds[] =
{
"gonarch/gon_step1.wav",
"gonarch/gon_step2.wav",
"gonarch/gon_step3.wav",
};
//=========================================================
// Spawn
//=========================================================
void CNPC_BigMomma::Spawn()
{
Precache( );
SetModel( "models/big_mom.mdl" );
UTIL_SetSize( this, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -