📄 hl1_npc_bigmomma.cpp
字号:
SetNavType( NAV_GROUND );
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_NOT_STANDABLE );
SetMoveType( MOVETYPE_STEP );
m_bloodColor = BLOOD_COLOR_GREEN;
m_iHealth = 150 * sk_bigmomma_health_factor.GetFloat();
SetHullType( HULL_WIDE_HUMAN );
SetHullSizeNormal();
CapabilitiesAdd( bits_CAP_MOVE_GROUND );
CapabilitiesAdd( bits_CAP_INNATE_RANGE_ATTACK1 | bits_CAP_INNATE_MELEE_ATTACK1 | bits_CAP_INNATE_MELEE_ATTACK2 );
// pev->view_ofs = Vector ( 0, 0, 128 );// position of the eyes relative to monster's origin.
m_flFieldOfView = 0.3;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_NPCState = NPC_STATE_NONE;
SetRenderColor( 255, 255, 255, 255 );
m_bDoneWithPath = false;
m_nodeTime = 0.0f;
m_iszTarget = m_iszNetName;
NPCInit();
BaseClass::Spawn();
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CNPC_BigMomma::Precache()
{
engine->PrecacheModel("models/big_mom.mdl");
PRECACHE_SOUND_ARRAY( pChildDieSounds );
PRECACHE_SOUND_ARRAY( pSackSounds );
PRECACHE_SOUND_ARRAY( pDeathSounds );
PRECACHE_SOUND_ARRAY( pAttackSounds );
PRECACHE_SOUND_ARRAY( pAttackHitSounds );
PRECACHE_SOUND_ARRAY( pBirthSounds );
PRECACHE_SOUND_ARRAY( pAlertSounds );
PRECACHE_SOUND_ARRAY( pPainSounds );
PRECACHE_SOUND_ARRAY( pFootSounds );
UTIL_PrecacheOther( BIG_CHILDCLASS );
// TEMP: Squid
engine->PrecacheModel("sprites/mommaspit.vmt");// spit projectile.
gSpitSprite = engine->PrecacheModel("sprites/mommaspout.vmt");// client side spittle.
gSpitDebrisSprite = engine->PrecacheModel("sprites/mommablob.vmt" );
enginesound->PrecacheSound( "bullchicken/bc_acid1.wav" );
enginesound->PrecacheSound( "bullchicken/bc_spithit1.wav" );
enginesound->PrecacheSound( "bullchicken/bc_spithit2.wav" );
}
//=========================================================
// SetYawSpeed - allows each sequence to have a different
// turn rate associated with it.
//=========================================================
float CNPC_BigMomma::MaxYawSpeed ( void )
{
float ys = 90.0f;
switch ( GetActivity() )
{
case ACT_IDLE:
ys = 100.0f;
break;
default:
ys = 90.0f;
}
return ys;
}
void CNPC_BigMomma::Activate( void )
{
if ( GetTarget() == NULL )
Remember( bits_MEMORY_ADVANCE_NODE ); // Start 'er up
BaseClass::Activate();
}
void CNPC_BigMomma::NodeStart( string_t iszNextNode )
{
m_iszTarget = iszNextNode;
const char *pTargetName = STRING( m_iszTarget );
CBaseEntity *pTarget = NULL;
if ( pTargetName )
pTarget = gEntList.FindEntityByName( NULL, pTargetName, NULL );
if ( pTarget == NULL )
{
//Msg( "BM: Finished the path!!\n" );
m_bDoneWithPath = true;
return;
}
SetTarget( pTarget );
}
void CNPC_BigMomma::NodeReach( void )
{
CInfoBM *pTarget = (CInfoBM*)GetTarget();
Forget( bits_MEMORY_ADVANCE_NODE );
if ( !pTarget )
return;
if ( pTarget->m_iHealth >= 1 )
m_iMaxHealth = m_iHealth = pTarget->m_iHealth * sk_bigmomma_health_factor.GetFloat();
if ( !HasMemory( bits_MEMORY_FIRED_NODE ) )
{
if ( pTarget )
{
pTarget->m_OnAnimationEvent.FireOutput( this, this );
}
}
Forget( bits_MEMORY_FIRED_NODE );
m_iszTarget = pTarget->m_target;
if ( pTarget->m_iHealth == 0 )
Remember( bits_MEMORY_ADVANCE_NODE ); // Move on if no health at this node
else
{
GetNavigator()->ClearGoal();
}
}
void CNPC_BigMomma::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr )
{
CTakeDamageInfo dmgInfo = info;
float flDamage = dmgInfo.GetDamage();
if ( ptr->hitbox <= 9 )
{
// didn't hit the sack?
if ( m_flDmgTime != gpGlobals->curtime || (RandomInt( 0, 10 ) < 1) )
{
CEffectData data;
data.m_vOrigin = ptr->endpos;
data.m_vAngles = GetAbsAngles();
data.m_vNormal = ( vecDir ) * -1;
DispatchEffect( "ManhackSparks", data );
m_flDmgTime = gpGlobals->curtime;
}
flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated
}
else
{
SpawnBlood( ptr->endpos + ptr->plane.normal * 15, m_bloodColor, 100 );
if ( gpGlobals->curtime > m_painSoundTime )
{
m_painSoundTime = gpGlobals->curtime + RandomInt(1, 3);
CPASAttenuationFilter filter( this );
EmitSound( filter, entindex(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pPainSounds ), 1.0f, ATTN_NORM, 0, 100 );
enginesound->EmitSound( filter, entindex(), CHAN_VOICE, pPainSounds[ random->RandomInt(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_NORM, 0, 100 );
}
}
BaseClass::TraceAttack( info, vecDir, ptr );
}
int CNPC_BigMomma::OnTakeDamage( const CTakeDamageInfo &info )
{
float flDamage = info.GetDamage();
// Don't take any acid damage -- BigMomma's mortar is acid
if ( info.GetDamageType() & DMG_ACID )
{
CTakeDamageInfo subInfo = info;
subInfo.SetDamage( 0 );
return BaseClass::OnTakeDamage( subInfo );
}
//Hacky McHack
if ( GetTask()->iTask == TASK_PLAY_NODE_PRESEQUENCE || GetTask()->iTask == TASK_PLAY_NODE_SEQUENCE )
return 0;
if ( m_bDoneWithPath == false )
{
if ( m_iHealth <= flDamage )
{
m_iHealth = flDamage + 1;
Remember( bits_MEMORY_ADVANCE_NODE );
//Msg( "BM: Finished node health!!!\n" );
}
}
return BaseClass::OnTakeDamage( info );
}
bool CNPC_BigMomma::ShouldGoToNode( void )
{
if ( HasMemory( bits_MEMORY_ADVANCE_NODE ) )
{
if ( m_nodeTime < gpGlobals->curtime )
return true;
}
return false;
}
int CNPC_BigMomma::SelectSchedule( void )
{
if ( ShouldGoToNode() )
{
return SCHED_BIG_NODE;
}
return BaseClass::SelectSchedule();
}
void CNPC_BigMomma::StartTask( const Task_t *pTask )
{
switch ( pTask->iTask )
{
case TASK_CHECK_NODE_PROXIMITY:
{
}
break;
case TASK_FIND_NODE:
{
CBaseEntity *pTarget = GetTarget();
if ( !HasMemory( bits_MEMORY_ADVANCE_NODE ) )
{
if ( pTarget )
m_iszTarget = pTarget->m_target;
}
NodeStart( m_iszTarget );
TaskComplete();
//Msg( "BM: Found node %s\n", STRING( m_iszTarget ) );
}
break;
case TASK_NODE_DELAY:
m_nodeTime = gpGlobals->curtime + pTask->flTaskData;
TaskComplete();
//Msg( "BM: FAIL! Delay %.2f\n", pTask->flTaskData );
break;
case TASK_PROCESS_NODE:
//Msg( "BM: Reached node %s\n", STRING( m_iszTarget ) );
NodeReach();
TaskComplete();
break;
case TASK_PLAY_NODE_PRESEQUENCE:
case TASK_PLAY_NODE_SEQUENCE:
{
const char *pSequence = NULL;
int iSequence;
if ( pTask->iTask == TASK_PLAY_NODE_SEQUENCE )
pSequence = GetNodeSequence();
else
pSequence = GetNodePresequence();
//Msg( "BM: Playing node sequence %s\n", pSequence );
if ( pSequence ) //ugh
{
iSequence = LookupSequence( pSequence );
if ( iSequence != -1 )
{
SetIdealActivity( ACT_DO_NOT_DISTURB );
SetSequence( iSequence );
m_flCycle = 0.0f;
ResetSequenceInfo();
//Msg( "BM: Sequence %s %f\n", GetNodeSequence(), gpGlobals->curtime );
return;
}
}
TaskComplete();
}
break;
case TASK_NODE_YAW:
GetMotor()->SetIdealYaw( GetNodeYaw() );
TaskComplete();
break;
case TASK_WAIT_NODE:
m_flWait = gpGlobals->curtime + GetNodeDelay();
/*if ( GetTarget() && GetTarget()->GetSpawnFlags() & SF_INFOBM_WAIT )
Msg( "BM: Wait at node %s forever\n", STRING( m_iszTarget) );
else
Msg( "BM: Wait at node %s for %.2f\n", STRING( m_iszTarget ), GetNodeDelay() );*/
break;
case TASK_MOVE_TO_NODE_RANGE:
{
CBaseEntity *pTarget = GetTarget();
if ( !pTarget )
TaskFail( FAIL_NO_TARGET );
else
{
if ( ( pTarget->GetAbsOrigin() - GetAbsOrigin() ).Length() < GetNodeRange() )
TaskComplete();
else
{
Activity act = ACT_WALK;
if ( pTarget->GetSpawnFlags() & SF_INFOBM_RUN )
act = ACT_RUN;
AI_NavGoal_t goal( GOALTYPE_TARGETENT, vec3_origin, act );
if ( !GetNavigator()->SetGoal( goal ) )
{
TaskFail( NO_TASK_FAILURE );
}
}
}
}
//Msg( "BM: Moving to node %s\n", STRING( m_iszTarget ) );
break;
case TASK_MELEE_ATTACK1:
{
// Play an attack sound here
CPASAttenuationFilter filter( this );
EmitSound( filter, entindex(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAttackSounds ), 1.0f, ATTN_NORM, 0, PITCH_NORM );
BaseClass::StartTask( pTask );
}
break;
default:
BaseClass::StartTask( pTask );
break;
}
}
//=========================================================
// RunTask
//=========================================================
void CNPC_BigMomma::RunTask( const Task_t *pTask )
{
switch ( pTask->iTask )
{
case TASK_CHECK_NODE_PROXIMITY:
{
float distance;
if ( GetTarget() == NULL )
TaskFail( FAIL_NO_TARGET );
else
{
if ( GetNavigator()->IsGoalActive() )
{
distance = ( GetTarget()->GetAbsOrigin() - GetAbsOrigin() ).Length2D();
// Set the appropriate activity based on an overlapping range
// overlap the range to prevent oscillation
if ( distance < GetNodeRange() )
{
//Msg( "BM: Reached node PROXIMITY!!\n" );
TaskComplete();
GetNavigator()->ClearGoal(); // Stop moving
}
}
else
TaskComplete();
}
}
break;
case TASK_WAIT_NODE:
if ( GetTarget() != NULL && (GetTarget()->GetSpawnFlags() & SF_INFOBM_WAIT) )
return;
if ( gpGlobals->curtime > m_flWaitFinished )
TaskComplete();
//Msg( "BM: The WAIT is over!\n" );
break;
case TASK_PLAY_NODE_PRESEQUENCE:
case TASK_PLAY_NODE_SEQUENCE:
if ( IsSequenceFinished() )
{
CBaseEntity *pTarget = NULL;
if ( GetTarget() )
pTarget = gEntList.FindEntityByName( NULL, STRING( GetTarget()->m_target ), NULL );
if ( pTarget )
{
SetActivity( ACT_IDLE );
TaskComplete();
}
}
break;
default:
BaseClass::RunTask( pTask );
break;
}
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
void CNPC_BigMomma::HandleAnimEvent( animevent_t *pEvent )
{
CPASAttenuationFilter filter( this );
Vector vecFwd, vecRight, vecUp;
QAngle angles;
angles = GetAbsAngles();
AngleVectors( angles, &vecFwd, &vecRight, &vecUp );
switch( pEvent->event )
{
case BIG_AE_MELEE_ATTACKBR:
case BIG_AE_MELEE_ATTACKBL:
case BIG_AE_MELEE_ATTACK1:
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -