Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
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.
 
 
 
 
 
 

395 lines
9.6 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "tf_walker_strider.h"
#include "npcevent.h"
#include "engine/IEngineSound.h"
#include "tf_gamerules.h"
#include "shake.h"
#include "in_buttons.h"
#include "studio.h"
#define STRIDER_AE_FOOTSTEP_LEFT 1
#define STRIDER_AE_FOOTSTEP_RIGHT 2
#define STRIDER_AE_FOOTSTEP_BACK 3
#define STRIDER_AE_FOOTSTEP_LEFTM 4
#define STRIDER_AE_FOOTSTEP_RIGHTM 5
#define STRIDER_AE_FOOTSTEP_BACKM 6
#define STRIDER_AE_FOOTSTEP_LEFTL 7
#define STRIDER_AE_FOOTSTEP_RIGHTL 8
#define STRIDER_AE_FOOTSTEP_BACKL 9
// How many inches/sec the strider's torso moves up and down to get the torso at the right height.
#define STRIDER_TORSO_VERTICAL_SLIDE_SPEED 100
#define STRIDER_FIRE_TIME 5
#define STRIDER_FIRE_INTERVAL 0.3
#define STRIDER_FIRE_ANGLE_ERROR 6 // N degrees of error when he fires.
#define WALKER_STRIDER_MODEL "models/objects/walker_strider.mdl"
IMPLEMENT_SERVERCLASS_ST( CWalkerStrider, DT_WalkerStrider )
SendPropInt( SENDINFO( m_bCrouched ), 1, SPROP_UNSIGNED )
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( walker_strider, CWalkerStrider );
PRECACHE_REGISTER( walker_strider );
char *g_StriderFeet[] =
{
"left foot",
"right foot",
"back foot"
};
#define NUM_STRIDER_FEET ARRAYSIZE( g_StriderFeet )
CWalkerStrider::CWalkerStrider()
{
m_bCrouched = false;
m_flOriginToLowestLegHeight = -1;
m_flWantedZ = -1;
m_bFiring = false;
m_vDriverAngles.Init();
}
void CWalkerStrider::Precache()
{
PrecacheModel( WALKER_STRIDER_MODEL );
PrecacheScriptSound( "Brush.Footstep" );
PrecacheScriptSound( "Brush.Fire" );
BaseClass::Precache();
}
void CWalkerStrider::Spawn()
{
SpawnWalker(
WALKER_STRIDER_MODEL, // Model name.
OBJ_WALKER_STRIDER, // Object type.
Vector( -186, -157, -504 ), // Placement dimensions.
Vector( 194, 159, 41 ),
200, // Health.
1, // Max passengers.
2.0 // 2x animation speed boost
);
}
bool CWalkerStrider::IsPassengerVisible( int nRole )
{
if ( nRole == VEHICLE_ROLE_DRIVER )
return false;
return true;
}
void CWalkerStrider::Fire()
{
EnableWalkMode( false );
m_bFiring = true;
m_flFireEndTime = gpGlobals->curtime + STRIDER_FIRE_TIME;
ResetSequence( LookupSequence( "shoot01a" ) );
m_flAnimTime = m_flPrevAnimTime = 0;
SetCycle( 0 );
m_flNextShootTime = gpGlobals->curtime;
m_vFireAngles[ROLL] = 0;
m_vFireAngles[PITCH] = m_vDriverAngles[PITCH];
m_vFireAngles[YAW] = GetAbsAngles()[YAW];
// Play the fire sound.
CPASAttenuationFilter filter( this, "Brush.Fire" );
EmitSound( filter, 0, "Brush.Fire", &GetAbsOrigin() );
}
void CWalkerStrider::Crouch()
{
// Disable the base class's walking functionality while we're crouched.
EnableWalkMode( false );
m_bCrouched = true;
m_flNextCrouchTime = gpGlobals->curtime + 0.3;
ResetSequence( LookupSequence( "low" ) );
// HACK: there should be a better way to this.. like CBaseAnimating::ResetAnimation,
// or ResetSequence should do it.
m_flAnimTime = m_flPrevAnimTime = 0;
SetCycle( 0 );
// HACK CITY.. This forces it to invalidate the abs origins of the gun bases.
Vector vPos = GetLocalOrigin();
SetLocalOrigin( vPos + Vector( 100, 0, 0 ) );
SetLocalOrigin( vPos );
}
void CWalkerStrider::UnCrouch()
{
EnableWalkMode( true );
m_flNextCrouchTime = gpGlobals->curtime + 0.3;
m_bCrouched = false;
// HACK CITY.. This forces it to invalidate the abs origins of the gun bases.
Vector vPos = GetLocalOrigin();
SetLocalOrigin( vPos + Vector( 100, 0, 0 ) );
SetLocalOrigin( vPos );
}
void CWalkerStrider::WalkerThink()
{
float dt = GetTimeDelta();
BaseClass::WalkerThink();
if ( m_bCrouched )
{
// Just sit there until they hit IN_DUCK again.
if ( (m_LastButtons & IN_DUCK) && gpGlobals->curtime > m_flNextCrouchTime )
{
UnCrouch();
}
}
else
{
if ( gpGlobals->curtime > m_flNextCrouchTime )
{
if ( m_LastButtons & IN_DUCK )
{
// They want to crouch.
Crouch();
}
else if ( !m_bFiring && (m_LastButtons & IN_ATTACK) )
{
Fire();
}
}
}
m_vDriverAngles = m_vLastCmdViewAngles;
if ( m_bCrouched )
{
// The "low" animation gets back up at the end so don't let that happen.
SetCycle( MIN( GetCycle(), 0.5f ) );
}
else if ( m_bFiring )
{
if ( gpGlobals->curtime > m_flFireEndTime )
{
m_bFiring = false;
EnableWalkMode( true );
}
else
{
// Shoot?
if ( gpGlobals->curtime >= m_flNextShootTime )
{
Vector vSrc = GetAbsOrigin();
Vector vForward;
QAngle vFireAngles = m_vFireAngles;
vFireAngles[YAW] += RandomFloat( -STRIDER_FIRE_ANGLE_ERROR, STRIDER_FIRE_ANGLE_ERROR );
vFireAngles[PITCH] += RandomFloat( -STRIDER_FIRE_ANGLE_ERROR, STRIDER_FIRE_ANGLE_ERROR );
AngleVectors( vFireAngles, &vForward );
trace_t trace;
UTIL_TraceLine( vSrc, vSrc + vForward * 2000, MASK_SOLID, this, COLLISION_GROUP_NONE, &trace );
Vector vHitPos = trace.endpos;
float flDamageRadius = 100;
float flDamage = 50;
CBasePlayer *pDriver = GetPassenger( VEHICLE_ROLE_DRIVER );
if ( pDriver )
{
UTIL_ImpactTrace( &trace, DMG_ENERGYBEAM, "Strider" );
// Tell the client entity to make a beam effect.
EntityMessageBegin( this, true );
WRITE_VEC3COORD( vHitPos );
MessageEnd();
UTIL_ScreenShake( vHitPos, 10.0, 150.0, 1.0, 100, SHAKE_START );
RadiusDamage( CTakeDamageInfo( this, pDriver, flDamage, DMG_BLAST ), vHitPos, flDamageRadius, CLASS_NONE, NULL );
}
m_flNextShootTime = gpGlobals->curtime + STRIDER_FIRE_INTERVAL;
}
}
}
else
{
// Move our torso within range of our feet.
if ( m_flOriginToLowestLegHeight != -1 )
{
trace_t trace;
UTIL_TraceLine(
GetAbsOrigin(),
GetAbsOrigin() - Vector( 0, 0, 2000 ),
MASK_SOLID_BRUSHONLY,
this,
COLLISION_GROUP_NONE,
&trace );
if ( trace.fraction < 1 )
{
m_flWantedZ = trace.endpos.z + m_flOriginToLowestLegHeight;
}
// Move our Z towards the wanted Z.
if ( m_flWantedZ != -1 )
{
Vector vCur = GetAbsOrigin();
vCur.z = Approach( m_flWantedZ, vCur.z, STRIDER_TORSO_VERTICAL_SLIDE_SPEED * dt );
SetAbsOrigin( vCur );
}
}
}
}
void CWalkerStrider::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
// Sapper removal
if ( RemoveEnemyAttachments( pActivator ) )
return;
CBaseTFPlayer *pPlayer = dynamic_cast<CBaseTFPlayer*>(pActivator);
if ( !pPlayer || !InSameTeam( pPlayer ) )
return;
// Ok, put them in the driver role.
AttemptToBoardVehicle( pPlayer );
}
void CWalkerStrider::SetupMove( CBasePlayer *pPlayer, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
{
BaseClass::SetupMove( pPlayer, ucmd, pHelper, move );
}
//
//
// This is a TOTAL hack, but we don't have any nodes that work well at all for mounted guns.
// This all goes away when we get a new model.
//
//
float sideDist = 90;
float downDist = -400;
bool CWalkerStrider::GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld )
{
CStudioHdr *pStudioHdr = GetModelPtr( );
if ( !pStudioHdr || iAttachment < 1 || iAttachment > pStudioHdr->GetNumAttachments() )
{
return false;
}
Vector vLocalPos( 0, 0, 0 );
const mstudioattachment_t &pAttachment = pStudioHdr->pAttachment( iAttachment-1 );
if ( stricmp( pAttachment.pszName(), "build_point_left_gun" ) == 0 )
{
vLocalPos.y = sideDist;
}
else if ( stricmp( pAttachment.pszName(), "build_point_right_gun" ) == 0 )
{
vLocalPos.y = -sideDist;
}
else if ( stricmp( pAttachment.pszName(), "ThirdPersonCameraOrigin" ) == 0 )
{
}
else
{
// Ok, it's not one of our magical attachments. Use the regular attachment setup stuff.
return BaseClass::GetAttachment( iAttachment, attachmentToWorld );
}
if ( m_bCrouched )
{
vLocalPos.z += downDist;
}
// Now build the output matrix.
matrix3x4_t localMatrix;
SetIdentityMatrix( localMatrix );
PositionMatrix( vLocalPos, localMatrix );
ConcatTransforms( EntityToWorldTransform(), localMatrix, attachmentToWorld );
return true;
}
bool CWalkerStrider::StartBuilding( CBaseEntity *pBuilder )
{
if ( !BaseClass::StartBuilding( pBuilder ) )
return false;
// Now figure out our ideal Z distance from our lowest foot to our torso.
Vector vOrigin;
QAngle vAngles;
BaseClass::GetAttachment( "left foot", vOrigin, vAngles );
m_flOriginToLowestLegHeight = GetAbsOrigin().z - vOrigin.z;
m_flOriginToLowestLegHeight -= 40; // fudge it a little so the legs have room to stretch.
return true;
}
void CWalkerStrider::FootHit( const char *pFootName )
{
if ( m_bCrouched || gpGlobals->curtime > m_flDontMakeSoundsUntil )
{
Vector footPosition;
QAngle angles;
((BaseClass*)this)->GetAttachment( pFootName, footPosition, angles );
CPASAttenuationFilter filter( this, "Brush.Footstep" );
EmitSound( filter, entindex(), "Brush.Footstep", &footPosition );
UTIL_ScreenShake( footPosition, 20.0, 1.0, 0.5, 200, SHAKE_START, false );
CBasePlayer *pPlayer = GetPassenger( VEHICLE_ROLE_DRIVER );
if ( pPlayer )
{
CTakeDamageInfo info( this, pPlayer, 20, DMG_CLUB );
TFGameRules()->RadiusDamage( info, footPosition, 200, CLASS_NONE );
}
m_flDontMakeSoundsUntil = gpGlobals->curtime + 0.4;
}
}
void CWalkerStrider::HandleAnimEvent( animevent_t *pEvent )
{
switch( pEvent->event )
{
case STRIDER_AE_FOOTSTEP_LEFT:
case STRIDER_AE_FOOTSTEP_LEFTM:
case STRIDER_AE_FOOTSTEP_LEFTL:
FootHit( "left foot" );
break;
case STRIDER_AE_FOOTSTEP_RIGHT:
case STRIDER_AE_FOOTSTEP_RIGHTM:
case STRIDER_AE_FOOTSTEP_RIGHTL:
FootHit( "right foot" );
break;
case STRIDER_AE_FOOTSTEP_BACK:
case STRIDER_AE_FOOTSTEP_BACKM:
case STRIDER_AE_FOOTSTEP_BACKL:
FootHit( "back foot" );
break;
}
}