mirror of
https://github.com/celisej567/source-sdk-2013.git
synced 2026-09-23 20:09:45 +03:00
- Overhauled matcher system and added expanded wildcard support, meaning "text", "te?t", "blah_test", etc. are now supported instead of only trailing * - Added support for regular expression matching - Added the missing matrixinvert.h file, which prevented programmers from compiling vbsp - Fixed env_global_light brightness - Added info_player_view_proxy, an entity which mimics a player's view (created for script_intro) - New UnZoomWithRate and SetZoomRate inputs on env_zoom - New "Don't change target's angles" flag on logic_measure_movement - Fixed logic_measure_movement not using ignore origin flags correctly - Fixed filter_damage_mod secondary filter not recognizing mode correctly - Fixed DisableGeigerCounter causing NPCs to ignore player, and possibly fixed other adverse effects in similar code - Added SetEntityName input for setting an entity's targetname - Added "SetTarget" support to point_posecontroller - Added "sk_alyx_health" convar for adjustable npc_alyx health, restored/fixed "sk_barney_health" for adjustable npc_barney health - Added ignore flags and several direction-related inputs to math_vector - Added pose parameter stuff to logic_modelinfo - Fixed ChangeWeapon not changing during combat - Fixed holster/unholster on NPCs without holster/unholster animations - Fixed func_tank and other "player in the way" code ignoring notarget - Added SetPoseParameter input to animating entities - Introduced an experimental chapter system which allows for custom chapter title/restriction management - Added SetChapterTitle input to worldspawn for dynamic title changing - Fixed func_tankairboatgun damage credit, added ability to use its damage keyvalues - Fixed mapbase_rpc_enabled not actually affecting RPC - Moved some newly found Combine soldier grenade code to ai_grenade for other grenade users - Fixed some problems with the new shared activities - Restored an old Mapbase entity as "prop_interactable", an entity which contains all of the functionality of a func_button/func_door in a prop entity - Added env_microphone pitch scale for scaling the pitch of transmitted sounds - Added experimental, long-overdue code for scenes to be able to access !target#'s and other scene-related names through AI_INPUT - Added "mat_specular_disable_on_missing", which "disables" specular reflections when the cubemap texture is missing - Fixed $envmapmasktransform and $bumptransform on VertexLitGeneric and related shaders - Areaportal leaks now stop compilation in leaktest - Replaced "-nodefaultcubemap" with "-defaultcubemap" as the shader changes allow maps to compile without default cubemaps by default with little effect
281 lines
7.4 KiB
C++
281 lines
7.4 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose: Alyx, the female sidekick and love interest that's taking the world by storm!
|
|
//
|
|
// Try the new Alyx Brite toothpaste!
|
|
// Alyx lederhosen!
|
|
//
|
|
// FIXME: need a better comment block
|
|
//
|
|
//=============================================================================//
|
|
|
|
#include "cbase.h"
|
|
#include "npcevent.h"
|
|
#include "ai_basenpc.h"
|
|
#include "ai_hull.h"
|
|
#include "ai_basehumanoid.h"
|
|
#include "npc_alyx.h"
|
|
#include "ai_senses.h"
|
|
#include "soundent.h"
|
|
#include "props.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
LINK_ENTITY_TO_CLASS( npc_alyx, CNPC_Alyx );
|
|
|
|
BEGIN_DATADESC( CNPC_Alyx )
|
|
|
|
DEFINE_FIELD( m_hEmpTool, FIELD_EHANDLE ),
|
|
|
|
END_DATADESC()
|
|
|
|
int AE_ALYX_EMPTOOL_ATTACHMENT;
|
|
int AE_ALYX_EMPTOOL_SEQUENCE;
|
|
|
|
#ifdef MAPBASE
|
|
ConVar sk_alyx_health( "sk_alyx_health", "80" );
|
|
#endif
|
|
|
|
//=========================================================
|
|
// Classify - indicates this NPC's place in the
|
|
// relationship table.
|
|
//=========================================================
|
|
Class_T CNPC_Alyx::Classify ( void )
|
|
{
|
|
return CLASS_PLAYER_ALLY_VITAL;
|
|
}
|
|
|
|
|
|
//=========================================================
|
|
// HandleAnimEvent - catches the NPC-specific messages
|
|
// that occur when tagged animation frames are played.
|
|
//=========================================================
|
|
void CNPC_Alyx::HandleAnimEvent( animevent_t *pEvent )
|
|
{
|
|
if (pEvent->event == AE_ALYX_EMPTOOL_ATTACHMENT)
|
|
{
|
|
if (!m_hEmpTool)
|
|
{
|
|
// Old savegame?
|
|
CreateEmpTool();
|
|
if (!m_hEmpTool)
|
|
return;
|
|
}
|
|
|
|
int iAttachment = LookupAttachment( pEvent->options );
|
|
m_hEmpTool->SetParent(this, iAttachment);
|
|
m_hEmpTool->SetLocalOrigin( Vector( 0, 0, 0 ) );
|
|
m_hEmpTool->SetLocalAngles( QAngle( 0, 0, 0 ) );
|
|
|
|
return;
|
|
}
|
|
else if (pEvent->event == AE_ALYX_EMPTOOL_SEQUENCE)
|
|
{
|
|
if (!m_hEmpTool)
|
|
return;
|
|
|
|
CDynamicProp *pEmpTool = dynamic_cast<CDynamicProp *>(m_hEmpTool.Get());
|
|
|
|
if (!pEmpTool)
|
|
return;
|
|
|
|
int iSequence = pEmpTool->LookupSequence( pEvent->options );
|
|
if (iSequence != ACT_INVALID)
|
|
{
|
|
pEmpTool->PropSetSequence( iSequence );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
switch( pEvent->event )
|
|
{
|
|
case 1:
|
|
default:
|
|
BaseClass::HandleAnimEvent( pEvent );
|
|
break;
|
|
}
|
|
}
|
|
|
|
//=========================================================
|
|
//
|
|
//=========================================================
|
|
bool CNPC_Alyx::CreateBehaviors()
|
|
{
|
|
return BaseClass::CreateBehaviors();
|
|
}
|
|
|
|
|
|
//=========================================================
|
|
// Spawn
|
|
//=========================================================
|
|
void CNPC_Alyx::Spawn()
|
|
{
|
|
BaseClass::Spawn();
|
|
|
|
// If Alyx has a parent, she's currently inside a pod. Prevent her from moving.
|
|
if ( GetMoveParent() )
|
|
{
|
|
SetMoveType( MOVETYPE_NONE );
|
|
CapabilitiesClear();
|
|
|
|
CapabilitiesAdd( bits_CAP_ANIMATEDFACE | bits_CAP_TURN_HEAD );
|
|
CapabilitiesAdd( bits_CAP_FRIENDLY_DMG_IMMUNE );
|
|
}
|
|
else
|
|
{
|
|
SetupAlyxWithoutParent();
|
|
CreateEmpTool( );
|
|
}
|
|
|
|
AddEFlags( EFL_NO_DISSOLVE | EFL_NO_MEGAPHYSCANNON_RAGDOLL | EFL_NO_PHYSCANNON_INTERACTION );
|
|
|
|
#ifdef MAPBASE
|
|
m_iHealth = sk_alyx_health.GetInt();
|
|
#else
|
|
m_iHealth = 80;
|
|
#endif
|
|
|
|
NPCInit();
|
|
}
|
|
|
|
//=========================================================
|
|
// Precache - precaches all resources this NPC needs
|
|
//=========================================================
|
|
void CNPC_Alyx::Precache()
|
|
{
|
|
BaseClass::Precache();
|
|
PrecacheScriptSound( "npc_alyx.die" );
|
|
PrecacheModel( STRING( GetModelName() ) );
|
|
PrecacheModel( "models/alyx_emptool_prop.mdl" );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CNPC_Alyx::SelectModel()
|
|
{
|
|
// Alyx is allowed to use multiple models, because she appears in the pod.
|
|
// She defaults to her normal model.
|
|
const char *szModel = STRING( GetModelName() );
|
|
if (!szModel || !*szModel)
|
|
{
|
|
SetModelName( AllocPooledString("models/alyx.mdl") );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CNPC_Alyx::SetupAlyxWithoutParent( void )
|
|
{
|
|
SetSolid( SOLID_BBOX );
|
|
AddSolidFlags( FSOLID_NOT_STANDABLE );
|
|
SetMoveType( MOVETYPE_STEP );
|
|
|
|
CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_DOORS_GROUP | bits_CAP_TURN_HEAD | bits_CAP_DUCK | bits_CAP_SQUAD );
|
|
CapabilitiesAdd( bits_CAP_USE_WEAPONS );
|
|
CapabilitiesAdd( bits_CAP_ANIMATEDFACE );
|
|
CapabilitiesAdd( bits_CAP_FRIENDLY_DMG_IMMUNE );
|
|
CapabilitiesAdd( bits_CAP_AIM_GUN );
|
|
CapabilitiesAdd( bits_CAP_MOVE_SHOOT );
|
|
CapabilitiesAdd( bits_CAP_USE_SHOT_REGULATOR );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CNPC_Alyx::CreateEmpTool( void )
|
|
{
|
|
m_hEmpTool = (CBaseAnimating*)CreateEntityByName( "prop_dynamic" );
|
|
if ( m_hEmpTool )
|
|
{
|
|
m_hEmpTool->SetModel( "models/alyx_emptool_prop.mdl" );
|
|
m_hEmpTool->SetName( AllocPooledString("Alyx_Emptool") );
|
|
int iAttachment = LookupAttachment( "Emp_Holster" );
|
|
m_hEmpTool->SetParent(this, iAttachment);
|
|
m_hEmpTool->SetOwnerEntity(this);
|
|
m_hEmpTool->SetSolid( SOLID_NONE );
|
|
m_hEmpTool->SetLocalOrigin( Vector( 0, 0, 0 ) );
|
|
m_hEmpTool->SetLocalAngles( QAngle( 0, 0, 0 ) );
|
|
m_hEmpTool->Spawn();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CNPC_Alyx::PrescheduleThink( void )
|
|
{
|
|
BaseClass::PrescheduleThink();
|
|
|
|
// Figure out if Alyx has just been removed from her parent
|
|
if ( GetMoveType() == MOVETYPE_NONE && !GetMoveParent() )
|
|
{
|
|
SetupAlyxWithoutParent();
|
|
SetupVPhysicsHull();
|
|
}
|
|
|
|
if ( HasCondition( COND_TALKER_PLAYER_DEAD ) )
|
|
{
|
|
SpeakIfAllowed( TLK_PLDEAD );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
Activity CNPC_Alyx::NPC_TranslateActivity( Activity activity )
|
|
{
|
|
activity = BaseClass::NPC_TranslateActivity( activity );
|
|
if ( activity == ACT_IDLE && (m_NPCState == NPC_STATE_COMBAT || m_NPCState == NPC_STATE_ALERT) )
|
|
{
|
|
if (gpGlobals->curtime - m_flLastAttackTime < 3 || gpGlobals->curtime - GetEnemyLastTimeSeen() < 8)
|
|
{
|
|
activity = ACT_IDLE_ANGRY;
|
|
}
|
|
}
|
|
|
|
return activity;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CNPC_Alyx::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
|
|
{
|
|
BaseClass::TraceAttack( info, vecDir, ptr, pAccumulator );
|
|
|
|
// FIXME: hack until some way of removing decals after healing
|
|
m_fNoDamageDecal = true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CNPC_Alyx::DeathSound( const CTakeDamageInfo &info )
|
|
{
|
|
// Sentences don't play on dead NPCs
|
|
SentenceStop();
|
|
|
|
EmitSound( "npc_alyx.die" );
|
|
}
|
|
|
|
//=========================================================
|
|
// AI Schedules Specific to this NPC
|
|
//=========================================================
|
|
|
|
AI_BEGIN_CUSTOM_NPC( npc_alyx, CNPC_Alyx )
|
|
|
|
DECLARE_ANIMEVENT( AE_ALYX_EMPTOOL_ATTACHMENT )
|
|
DECLARE_ANIMEVENT( AE_ALYX_EMPTOOL_SEQUENCE )
|
|
|
|
AI_END_CUSTOM_NPC()
|
|
|