You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
307 lines
7.8 KiB
307 lines
7.8 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: A slow-moving, once-human headcrab victim with only melee attacks. |
|
// |
|
// UNDONE: Make head take 100% damage, body take 30% damage. |
|
// UNDONE: Don't flinch every time you get hit. |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "game.h" |
|
#include "ai_default.h" |
|
#include "ai_schedule.h" |
|
#include "ai_hull.h" |
|
#include "ai_route.h" |
|
#include "npcevent.h" |
|
#include "hl1_npc_zombie.h" |
|
#include "gib.h" |
|
//#include "AI_Interactions.h" |
|
#include "ndebugoverlay.h" |
|
#include "vstdlib/random.h" |
|
#include "engine/IEngineSound.h" |
|
|
|
ConVar sk_zombie_health( "sk_zombie_health","50"); |
|
ConVar sk_zombie_dmg_one_slash( "sk_zombie_dmg_one_slash", "20" ); |
|
ConVar sk_zombie_dmg_both_slash( "sk_zombie_dmg_both_slash", "40" ); |
|
|
|
|
|
|
|
LINK_ENTITY_TO_CLASS( monster_zombie, CNPC_Zombie ); |
|
|
|
|
|
//========================================================= |
|
// Spawn |
|
//========================================================= |
|
void CNPC_Zombie::Spawn() |
|
{ |
|
Precache( ); |
|
|
|
SetModel( "models/zombie.mdl" ); |
|
|
|
SetRenderColor( 255, 255, 255, 255 ); |
|
|
|
SetHullType(HULL_HUMAN); |
|
SetHullSizeNormal(); |
|
|
|
SetSolid( SOLID_BBOX ); |
|
AddSolidFlags( FSOLID_NOT_STANDABLE ); |
|
SetMoveType( MOVETYPE_STEP ); |
|
m_bloodColor = BLOOD_COLOR_GREEN; |
|
m_iHealth = sk_zombie_health.GetFloat(); |
|
//pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin. |
|
m_flFieldOfView = 0.5; |
|
m_NPCState = NPC_STATE_NONE; |
|
CapabilitiesClear(); |
|
CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_INNATE_MELEE_ATTACK1 | bits_CAP_DOORS_GROUP ); |
|
|
|
NPCInit(); |
|
} |
|
|
|
//========================================================= |
|
// Precache - precaches all resources this monster needs |
|
//========================================================= |
|
void CNPC_Zombie::Precache() |
|
{ |
|
PrecacheModel( "models/zombie.mdl" ); |
|
|
|
PrecacheScriptSound( "Zombie.AttackHit" ); |
|
PrecacheScriptSound( "Zombie.AttackMiss" ); |
|
PrecacheScriptSound( "Zombie.Pain" ); |
|
PrecacheScriptSound( "Zombie.Idle" ); |
|
PrecacheScriptSound( "Zombie.Alert" ); |
|
PrecacheScriptSound( "Zombie.Attack" ); |
|
|
|
BaseClass::Precache(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns this monster's place in the relationship table. |
|
//----------------------------------------------------------------------------- |
|
Class_T CNPC_Zombie::Classify( void ) |
|
{ |
|
return CLASS_ALIEN_MONSTER; |
|
} |
|
|
|
//========================================================= |
|
// HandleAnimEvent - catches the monster-specific messages |
|
// that occur when tagged animation frames are played. |
|
//========================================================= |
|
void CNPC_Zombie::HandleAnimEvent( animevent_t *pEvent ) |
|
{ |
|
Vector v_forward, v_right; |
|
switch( pEvent->event ) |
|
{ |
|
case ZOMBIE_AE_ATTACK_RIGHT: |
|
{ |
|
// do stuff for this event. |
|
// ALERT( at_console, "Slash right!\n" ); |
|
|
|
Vector vecMins = GetHullMins(); |
|
Vector vecMaxs = GetHullMaxs(); |
|
vecMins.z = vecMins.x; |
|
vecMaxs.z = vecMaxs.x; |
|
|
|
CBaseEntity *pHurt = CheckTraceHullAttack( 70, vecMins, vecMaxs, sk_zombie_dmg_one_slash.GetFloat(), DMG_SLASH ); |
|
CPASAttenuationFilter filter( this ); |
|
if ( pHurt ) |
|
{ |
|
if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) ) |
|
{ |
|
pHurt->ViewPunch( QAngle( 5, 0, 18 ) ); |
|
|
|
GetVectors( &v_forward, &v_right, NULL ); |
|
|
|
pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() - v_right * 100 ); |
|
} |
|
// Play a random attack hit sound |
|
EmitSound( filter, entindex(), "Zombie.AttackHit" ); |
|
} |
|
else // Play a random attack miss sound |
|
EmitSound( filter, entindex(), "Zombie.AttackMiss" ); |
|
|
|
if ( random->RandomInt( 0, 1 ) ) |
|
AttackSound(); |
|
} |
|
break; |
|
|
|
case ZOMBIE_AE_ATTACK_LEFT: |
|
{ |
|
// do stuff for this event. |
|
// ALERT( at_console, "Slash left!\n" ); |
|
Vector vecMins = GetHullMins(); |
|
Vector vecMaxs = GetHullMaxs(); |
|
vecMins.z = vecMins.x; |
|
vecMaxs.z = vecMaxs.x; |
|
|
|
CBaseEntity *pHurt = CheckTraceHullAttack( 70, vecMins, vecMaxs, sk_zombie_dmg_one_slash.GetFloat(), DMG_SLASH ); |
|
|
|
CPASAttenuationFilter filter2( this ); |
|
if ( pHurt ) |
|
{ |
|
if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) ) |
|
{ |
|
pHurt->ViewPunch( QAngle ( 5, 0, -18 ) ); |
|
|
|
GetVectors( &v_forward, &v_right, NULL ); |
|
|
|
pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() - v_right * 100 ); |
|
} |
|
EmitSound( filter2, entindex(), "Zombie.AttackHit" ); |
|
} |
|
else |
|
{ |
|
EmitSound( filter2, entindex(), "Zombie.AttackMiss" ); |
|
} |
|
|
|
if ( random->RandomInt( 0,1 ) ) |
|
AttackSound(); |
|
} |
|
break; |
|
|
|
case ZOMBIE_AE_ATTACK_BOTH: |
|
{ |
|
// do stuff for this event. |
|
Vector vecMins = GetHullMins(); |
|
Vector vecMaxs = GetHullMaxs(); |
|
vecMins.z = vecMins.x; |
|
vecMaxs.z = vecMaxs.x; |
|
|
|
CBaseEntity *pHurt = CheckTraceHullAttack( 70, vecMins, vecMaxs, sk_zombie_dmg_both_slash.GetFloat(), DMG_SLASH ); |
|
|
|
|
|
CPASAttenuationFilter filter3( this ); |
|
if ( pHurt ) |
|
{ |
|
if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) ) |
|
{ |
|
pHurt->ViewPunch( QAngle ( 5, 0, 0 ) ); |
|
|
|
GetVectors( &v_forward, &v_right, NULL ); |
|
pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() - v_right * 100 ); |
|
} |
|
EmitSound( filter3, entindex(), "Zombie.AttackHit" ); |
|
} |
|
else |
|
EmitSound( filter3, entindex(),"Zombie.AttackMiss" ); |
|
|
|
if ( random->RandomInt( 0,1 ) ) |
|
AttackSound(); |
|
} |
|
break; |
|
|
|
default: |
|
BaseClass::HandleAnimEvent( pEvent ); |
|
break; |
|
} |
|
} |
|
|
|
|
|
static float DamageForce( const Vector &size, float damage ) |
|
{ |
|
float force = damage * ((32 * 32 * 72.0) / (size.x * size.y * size.z)) * 5; |
|
|
|
if ( force > 1000.0) |
|
{ |
|
force = 1000.0; |
|
} |
|
|
|
return force; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : pInflictor - |
|
// pAttacker - |
|
// flDamage - |
|
// bitsDamageType - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
int CNPC_Zombie::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo ) |
|
{ |
|
CTakeDamageInfo info = inputInfo; |
|
|
|
// Take 30% damage from bullets |
|
if ( info.GetDamageType() == DMG_BULLET ) |
|
{ |
|
Vector vecDir = GetAbsOrigin() - info.GetInflictor()->WorldSpaceCenter(); |
|
VectorNormalize( vecDir ); |
|
float flForce = DamageForce( WorldAlignSize(), info.GetDamage() ); |
|
SetAbsVelocity( GetAbsVelocity() + vecDir * flForce ); |
|
info.ScaleDamage( 0.3f ); |
|
} |
|
|
|
// HACK HACK -- until we fix this. |
|
if ( IsAlive() ) |
|
PainSound( info ); |
|
|
|
return BaseClass::OnTakeDamage_Alive( info ); |
|
} |
|
|
|
void CNPC_Zombie::PainSound( const CTakeDamageInfo &info ) |
|
{ |
|
if ( random->RandomInt(0,5) < 2) |
|
{ |
|
CPASAttenuationFilter filter( this ); |
|
EmitSound( filter, entindex(), "Zombie.Pain" ); |
|
} |
|
} |
|
|
|
void CNPC_Zombie::AlertSound( void ) |
|
{ |
|
CPASAttenuationFilter filter( this ); |
|
EmitSound( filter, entindex(), "Zombie.Alert" ); |
|
} |
|
|
|
void CNPC_Zombie::IdleSound( void ) |
|
{ |
|
// Play a random idle sound |
|
CPASAttenuationFilter filter( this ); |
|
EmitSound( filter, entindex(), "Zombie.Idle" ); |
|
} |
|
|
|
void CNPC_Zombie::AttackSound( void ) |
|
{ |
|
// Play a random attack sound |
|
CPASAttenuationFilter filter( this ); |
|
EmitSound( filter, entindex(), "Zombie.Attack" ); |
|
} |
|
|
|
int CNPC_Zombie::MeleeAttack1Conditions ( float flDot, float flDist ) |
|
{ |
|
if ( flDist > 64) |
|
{ |
|
return COND_TOO_FAR_TO_ATTACK; |
|
} |
|
else if (flDot < 0.7) |
|
{ |
|
return 0; |
|
} |
|
else if (GetEnemy() == NULL) |
|
{ |
|
return 0; |
|
} |
|
|
|
return COND_CAN_MELEE_ATTACK1; |
|
} |
|
|
|
void CNPC_Zombie::RemoveIgnoredConditions ( void ) |
|
{ |
|
if ( GetActivity() == ACT_MELEE_ATTACK1 ) |
|
{ |
|
// Nothing stops an attacking zombie. |
|
ClearCondition( COND_LIGHT_DAMAGE ); |
|
ClearCondition( COND_HEAVY_DAMAGE ); |
|
} |
|
|
|
if (( GetActivity() == ACT_SMALL_FLINCH ) || ( GetActivity() == ACT_BIG_FLINCH )) |
|
{ |
|
if (m_flNextFlinch < gpGlobals->curtime) |
|
m_flNextFlinch = gpGlobals->curtime + ZOMBIE_FLINCH_DELAY; |
|
} |
|
|
|
BaseClass::RemoveIgnoredConditions(); |
|
}
|
|
|