📄 hl1_npc_bigmomma.cpp
字号:
Vector center = GetAbsOrigin() + vecFwd * 128;
Vector mins = center - Vector( 64, 64, 0 );
Vector maxs = center + Vector( 64, 64, 64 );
CBaseEntity *pList[8];
int count = UTIL_EntitiesInBox( pList, 8, mins, maxs, FL_NPC | FL_CLIENT );
CBaseEntity *pHurt = NULL;
for ( int i = 0; i < count && !pHurt; i++ )
{
if ( pList[i] != this )
{
if ( pList[i]->GetOwnerEntity() != this )
{
pHurt = pList[i];
}
}
}
if ( pHurt )
{
CTakeDamageInfo info( this, this, 15, DMG_CLUB | DMG_SLASH );
CalculateMeleeDamageForce( &info, (pHurt->GetAbsOrigin() - GetAbsOrigin()), pHurt->GetAbsOrigin() );
pHurt->TakeDamage( info );
QAngle newAngles = angles;
newAngles.x = 15;
if ( pHurt->IsPlayer() )
{
((CBasePlayer *)pHurt)->SetPunchAngle( newAngles );
}
switch( pEvent->event )
{
case BIG_AE_MELEE_ATTACKBR:
// pHurt->pev->velocity = pHurt->pev->velocity + (vecFwd * 150) + Vector(0,0,250) - (vecRight * 200);
pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 150) + Vector(0,0,250) - (vecRight * 200) );
break;
case BIG_AE_MELEE_ATTACKBL:
pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 150) + Vector(0,0,250) + (vecRight * 200) );
break;
case BIG_AE_MELEE_ATTACK1:
pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 220) + Vector(0,0,200) );
break;
}
pHurt->RemoveFlag( FL_ONGROUND );
enginesound->EmitSound( filter, entindex(), CHAN_BODY, pAttackHitSounds[ random->RandomInt(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RandomInt(-5,5) );
}
}
break;
case BIG_AE_SCREAM:
enginesound->EmitSound( filter, entindex(), CHAN_BODY, pAlertSounds[ random->RandomInt(0,ARRAYSIZE(pAlertSounds)-1) ], 1.0, ATTN_NORM, 0, 100 );
break;
case BIG_AE_PAIN_SOUND:
enginesound->EmitSound( filter, entindex(), CHAN_BODY, pPainSounds[ random->RandomInt(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_NORM, 0, 100 );
break;
case BIG_AE_ATTACK_SOUND:
enginesound->EmitSound( filter, entindex(), CHAN_BODY, pAttackSounds[ random->RandomInt(0,ARRAYSIZE(pAttackSounds)-1) ], 1.0, ATTN_NORM, 0, 100 );
break;
case BIG_AE_BIRTH_SOUND:
enginesound->EmitSound( filter, entindex(), CHAN_BODY, pBirthSounds[ random->RandomInt(0,ARRAYSIZE(pBirthSounds)-1) ], 1.0, ATTN_NORM, 0, 100 );
break;
case BIG_AE_SACK:
if ( RandomInt(0,100) < 30 )
{
enginesound->EmitSound( filter, entindex(), CHAN_BODY, pSackSounds[ random->RandomInt(0,ARRAYSIZE(pSackSounds)-1) ], 1.0, ATTN_NORM, 0, 100 );
}
break;
case BIG_AE_DEATHSOUND:
enginesound->EmitSound( filter, entindex(), CHAN_BODY, pDeathSounds[ random->RandomInt(0,ARRAYSIZE(pDeathSounds)-1) ], 1.0, ATTN_NORM, 0, 100 );
break;
case BIG_AE_STEP1: // Footstep left
case BIG_AE_STEP3: // Footstep back left
enginesound->EmitSound( filter, entindex(), CHAN_ITEM, pFootSounds[ random->RandomInt(0,ARRAYSIZE(pFootSounds)-1) ], 1.0, ATTN_NORM, 0, 100 );
break;
case BIG_AE_STEP4: // Footstep back right
case BIG_AE_STEP2: // Footstep right
enginesound->EmitSound( filter, entindex(), CHAN_BODY, pFootSounds[ random->RandomInt(0,ARRAYSIZE(pFootSounds)-1) ], 1.0, ATTN_NORM, 0, 100 );
break;
case BIG_AE_MORTAR_ATTACK1:
LaunchMortar();
break;
case BIG_AE_LAY_CRAB:
LayHeadcrab();
break;
case BIG_AE_JUMP_FORWARD:
RemoveFlag( FL_ONGROUND );
SetAbsOrigin(GetAbsOrigin() + Vector ( 0 , 0 , 1) );// take him off ground so engine doesn't instantly reset onground
SetAbsVelocity(vecFwd * 200 + vecUp * 500 );
break;
case BIG_AE_EARLY_TARGET:
{
CInfoBM *pTarget = (CInfoBM*) GetTarget();
if ( pTarget )
{
pTarget->m_OnAnimationEvent.FireOutput( this, this );
}
Remember( bits_MEMORY_FIRED_NODE );
}
break;
default:
BaseClass::HandleAnimEvent( pEvent );
break;
}
}
void CNPC_BigMomma::LayHeadcrab( void )
{
CBaseEntity *pChild = CBaseEntity::Create( BIG_CHILDCLASS, GetAbsOrigin(), GetAbsAngles(), this );
pChild->AddSpawnFlags( SF_NPC_FALL_TO_GROUND );
pChild->SetOwnerEntity( this );
// Is this the second crab in a pair?
if ( HasMemory( bits_MEMORY_CHILDPAIR ) )
{
m_crabTime = gpGlobals->curtime + RandomFloat( 5, 10 );
Forget( bits_MEMORY_CHILDPAIR );
}
else
{
m_crabTime = gpGlobals->curtime + RandomFloat( 0.5, 2.5 );
Remember( bits_MEMORY_CHILDPAIR );
}
trace_t tr;
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector(0,0,100), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
UTIL_DecalTrace( &tr, "Splash" );
CPASAttenuationFilter filter( this );
enginesound->EmitSound( filter, entindex(), CHAN_WEAPON, pBirthSounds[ random->RandomInt(0,ARRAYSIZE(pBirthSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + random->RandomInt(-5,5) );
m_crabCount++;
}
void CNPC_BigMomma::DeathNotice( CBaseEntity *pevChild )
{
if ( m_crabCount > 0 ) // Some babies may cross a transition, but we reset the count then
{
m_crabCount--;
}
if ( IsAlive() )
{
// Make the "my baby's dead" noise!
CPASAttenuationFilter filter( this );
EmitSound( filter, entindex(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pChildDieSounds ), 1.0f, ATTN_NORM, 0, PITCH_NORM );
enginesound->EmitSound( filter, entindex(), CHAN_WEAPON, pBirthSounds[ random->RandomInt(0,ARRAYSIZE(pBirthSounds)-1) ], 1.0, ATTN_NORM, 0, 100 );
}
}
void CNPC_BigMomma::LaunchMortar( void )
{
m_mortarTime = gpGlobals->curtime + RandomFloat( 2, 15 );
Vector startPos = GetAbsOrigin();
startPos.z += 180;
CPASAttenuationFilter filter( this );
enginesound->EmitSound( filter, entindex(), CHAN_WEAPON, pSackSounds[ random->RandomInt(0,ARRAYSIZE(pSackSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + random->RandomInt(-5,5) );
CBMortar *pBomb = CBMortar::Shoot( this, startPos, m_vTossDir );
pBomb->SetGravity( 1.0 );
MortarSpray( startPos, Vector(0,0,10), gSpitSprite, 24 );
}
int CNPC_BigMomma::MeleeAttack1Conditions( float flDot, float flDist )
{
if (flDot >= 0.7)
{
if ( flDist > BIG_ATTACKDIST )
return COND_TOO_FAR_TO_ATTACK;
else
return COND_CAN_MELEE_ATTACK1;
}
else
{
return COND_NOT_FACING_ATTACK;
}
return COND_NONE;
}
// Lay a crab
int CNPC_BigMomma::MeleeAttack2Conditions( float flDot, float flDist )
{
return CanLayCrab();
}
Vector VecCheckSplatToss( CBaseEntity *pEnt, const Vector &vecSpot1, Vector vecSpot2, float maxHeight )
{
trace_t tr;
Vector vecMidPoint;// halfway point between Spot1 and Spot2
Vector vecApex;// highest point
Vector vecScale;
Vector vecGrenadeVel;
Vector vecTemp;
float flGravity = sv_gravity.GetFloat();
// calculate the midpoint and apex of the 'triangle'
vecMidPoint = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5;
UTIL_TraceLine(vecMidPoint, vecMidPoint + Vector(0,0,maxHeight), MASK_SOLID_BRUSHONLY, pEnt, COLLISION_GROUP_NONE, &tr );
vecApex = tr.endpos;
UTIL_TraceLine(vecSpot1, vecApex, MASK_SOLID, pEnt, COLLISION_GROUP_NONE, &tr );
if (tr.fraction != 1.0)
{
// fail!
return vec3_origin;
}
// Don't worry about actually hitting the target, this won't hurt us!
// How high should the grenade travel (subtract 15 so the grenade doesn't hit the ceiling)?
float height = (vecApex.z - vecSpot1.z) - 15;
//HACK HACK
if ( height < 0 )
height *= -1;
// How fast does the grenade need to travel to reach that height given gravity?
float speed = sqrt( 2 * flGravity * height );
// How much time does it take to get there?
float time = speed / flGravity;
vecGrenadeVel = (vecSpot2 - vecSpot1);
vecGrenadeVel.z = 0;
// Travel half the distance to the target in that time (apex is at the midpoint)
vecGrenadeVel = vecGrenadeVel * ( 0.5 / time );
// Speed to offset gravity at the desired height
vecGrenadeVel.z = speed;
return vecGrenadeVel;
}
// Mortar launch
int CNPC_BigMomma::RangeAttack1Conditions( float flDot, float flDist )
{
if ( flDist > BIG_MORTARDIST )
return COND_TOO_FAR_TO_ATTACK;
if ( flDist <= BIG_MORTARDIST && m_mortarTime < gpGlobals->curtime )
{
CBaseEntity *pEnemy = GetEnemy();
if ( pEnemy )
{
Vector startPos = GetAbsOrigin();
startPos.z += 180;
m_vTossDir = VecCheckSplatToss( this, startPos, pEnemy->BodyTarget( GetAbsOrigin() ), random->RandomFloat( 150, 500 ) );
if ( m_vTossDir != vec3_origin )
return COND_CAN_RANGE_ATTACK1;
}
}
return COND_NONE;
}
// ---------------------------------
//
// Mortar
//
// ---------------------------------
void MortarSpray( const Vector &position, const Vector &direction, int spriteModel, int count )
{
CPVSFilter filter( position );
te->SpriteSpray( filter, 0.0, &position, &direction, spriteModel, 200, 80, count );
}
// UNDONE: right now this is pretty much a copy of the squid spit with minor changes to the way it does damage
void CBMortar:: Spawn( void )
{
SetMoveType( MOVETYPE_FLYGRAVITY );
SetClassname( "bmortar" );
SetSolid( SOLID_BBOX );
pSprite = CSprite::SpriteCreate( "sprites/mommaspit.vmt", GetAbsOrigin(), true );
if ( pSprite )
{
pSprite->SetAttachment( this, 0 );
pSprite->m_flSpriteFramerate = 5;
pSprite->m_nRenderMode = kRenderTransAlpha;
pSprite->SetBrightness( 255 );
m_iFrame = 0;
pSprite->SetScale( 2.5f );
}
UTIL_SetSize( this, Vector( 0, 0, 0), Vector(0, 0, 0) );
m_maxFrame = (float)modelinfo->GetModelFrameCount( GetModel() ) - 1;
m_flDmgTime = gpGlobals->curtime + 0.4;
}
void CBMortar::Animate( void )
{
SetNextThink( gpGlobals->curtime + 0.1 );
Vector vVelocity = GetAbsVelocity();
VectorNormalize( vVelocity );
if ( gpGlobals->curtime > m_flDmgTime )
{
m_flDmgTime = gpGlobals->curtime + 0.2;
MortarSpray( GetAbsOrigin() + Vector( 0, 0, 15 ), -vVelocity, gSpitSprite, 3 );
}
if ( m_iFrame++ )
{
if ( m_iFrame > m_maxFrame )
{
m_iFrame = 0;
}
}
}
CBMortar *CBMortar::Shoot( CBaseEntity *pOwner, Vector vecStart, Vector vecVelocity )
{
CBMortar *pSpit = CREATE_ENTITY( CBMortar, "bmortar" );
pSpit->Spawn();
UTIL_SetOrigin( pSpit, vecStart );
pSpit->SetAbsVelocity( vecVelocity );
pSpit->SetOwnerEntity( pOwner );
pSpit->SetThink ( &CBMortar::Animate );
pSpit->SetNextThink( gpGlobals->curtime + 0.1 );
return pSpit;
}
void CBMortar::Touch( CBaseEntity *pOther )
{
trace_t tr;
int iPitch;
// splat sound
iPitch = random->RandomFloat( 90, 110 );
EmitSound( "NPC_BigMomma.SpitTouch1" );
switch ( random->RandomInt( 0, 1 ) )
{
case 0:
EmitSound( "NPC_BigMomma.SpitHit1" );
break;
case 1:
EmitSound( "NPC_BigMomma.SpitHit2" );
break;
}
if ( pOther->IsBSPModel() )
{
// make a splat on the wall
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + GetAbsVelocity() * 10, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
UTIL_DecalTrace( &tr, "Splash" );
}
else
{
tr.endpos = GetAbsOrigin();
Vector vVelocity = GetAbsVelocity();
VectorNormalize( vVelocity );
tr.plane.normal = -1 * vVelocity;
}
// make some flecks
MortarSpray( tr.endpos + Vector( 0, 0, 15 ), tr.plane.normal, gSpitSprite, 24 );
CBaseEntity *pOwner = GetOwnerEntity();
RadiusDamage( CTakeDamageInfo( this, pOwner, sk_bigmomma_dmg_blast.GetFloat(), DMG_ACID ), GetAbsOrigin(), sk_bigmomma_radius_blast.GetFloat(), CLASS_NONE );
UTIL_Remove( pSprite );
UTIL_Remove( this );
}
AI_BEGIN_CUSTOM_NPC( monster_bigmomma, CNPC_BigMomma )
DECLARE_TASK( TASK_MOVE_TO_NODE_RANGE )
DECLARE_TASK( TASK_FIND_NODE )
DECLARE_TASK( TASK_PLAY_NODE_PRESEQUENCE )
DECLARE_TASK( TASK_PLAY_NODE_SEQUENCE )
DECLARE_TASK( TASK_PROCESS_NODE )
DECLARE_TASK( TASK_WAIT_NODE )
DECLARE_TASK( TASK_NODE_DELAY )
DECLARE_TASK( TASK_NODE_YAW )
DECLARE_TASK( TASK_CHECK_NODE_PROXIMITY )
//=========================================================
// > SCHED_BIG_NODE
//=========================================================
DEFINE_SCHEDULE
(
SCHED_NODE_FAIL,
" Tasks"
" TASK_NODE_DELAY 3"
" TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
" "
" Interrupts"
)
//=========================================================
// > SCHED_BIG_NODE
//=========================================================
DEFINE_SCHEDULE
(
SCHED_BIG_NODE,
" Tasks"
" TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_NODE_FAIL"
" TASK_STOP_MOVING 0"
" TASK_FIND_NODE 0"
" TASK_PLAY_NODE_PRESEQUENCE 0"
" TASK_MOVE_TO_NODE_RANGE 0"
" TASK_CHECK_NODE_PROXIMITY 0"
" TASK_STOP_MOVING 0"
" TASK_NODE_YAW 0"
" TASK_FACE_IDEAL 0"
" TASK_WAIT_NODE 0"
" TASK_PLAY_NODE_SEQUENCE 0"
" TASK_PROCESS_NODE 0"
" "
" Interrupts"
)
AI_END_CUSTOM_NPC()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -