mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-23 06:36:54 +00:00
516 lines
11 KiB
C++
516 lines
11 KiB
C++
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
//=============================================================================//
|
||
|
|
||
|
#include "cbase.h"
|
||
|
#include "tf_walker_ministrider.h"
|
||
|
#include "in_buttons.h"
|
||
|
#include "studio.h"
|
||
|
#include "shake.h"
|
||
|
#include "tf_gamerules.h"
|
||
|
#include "npcevent.h"
|
||
|
#include "ndebugoverlay.h"
|
||
|
#include "te_effect_dispatch.h"
|
||
|
#include "beam_shared.h"
|
||
|
#include "ai_activity.h"
|
||
|
|
||
|
#define WALKER_MINI_STRIDER_MODEL "models/objects/alien_vehicle_strider.mdl"
|
||
|
#define STRIDER_TORSO_VERTICAL_SLIDE_SPEED 100
|
||
|
|
||
|
float LARGE_GUN_FIRE_TIME = 3;
|
||
|
|
||
|
// Skirmisher CVars
|
||
|
ConVar tf_skirmisher_speed( "tf_skirmisher_speed", "300" );
|
||
|
ConVar tf_skirmisher_machinegun_range( "tf_skirmisher_machinegun_range", "2000" );
|
||
|
ConVar tf_skirmisher_machinegun_damage( "tf_skirmisher_machinegun_damage", "20" );
|
||
|
ConVar tf_skirmisher_machinegun_rof( "tf_skirmisher_machinegun_rof", "10" );
|
||
|
|
||
|
IMPLEMENT_SERVERCLASS_ST( CWalkerMiniStrider, DT_WalkerMiniStrider )
|
||
|
END_SEND_TABLE()
|
||
|
|
||
|
LINK_ENTITY_TO_CLASS( walker_mini_strider, CWalkerMiniStrider );
|
||
|
PRECACHE_REGISTER( walker_mini_strider );
|
||
|
|
||
|
|
||
|
|
||
|
CWalkerMiniStrider::CWalkerMiniStrider()
|
||
|
{
|
||
|
m_flWantedZ = -1;
|
||
|
m_bFiringMachineGun = m_bFiringLargeGun = false;
|
||
|
m_flOriginToLowestLegHeight = 133;
|
||
|
m_State = STATE_NORMAL;
|
||
|
m_bFiringLeftGun = true;
|
||
|
m_flNextFootstepSoundTime = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
CWalkerMiniStrider::~CWalkerMiniStrider()
|
||
|
{
|
||
|
UTIL_Remove( m_pEnergyBeam );
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::Precache()
|
||
|
{
|
||
|
PrecacheModel( WALKER_MINI_STRIDER_MODEL );
|
||
|
|
||
|
PrecacheScriptSound( "Skirmisher.Footstep" );
|
||
|
PrecacheScriptSound( "Skirmisher.GunSound" );
|
||
|
PrecacheScriptSound( "Skirmisher.GunChargeSound" );
|
||
|
|
||
|
BaseClass::Precache();
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::Spawn()
|
||
|
{
|
||
|
SpawnWalker(
|
||
|
WALKER_MINI_STRIDER_MODEL, // Model name.
|
||
|
OBJ_WALKER_MINI_STRIDER, // Object type.
|
||
|
Vector( 0, 0, 140 ) + Vector( -100, -100, -100 ), // Placement dimensions.
|
||
|
Vector( 0, 0, 140 ) + Vector( 100, 100, 100 ),
|
||
|
200, // Health.
|
||
|
1, // Max passengers.
|
||
|
1.0 // 1x speed multiplier
|
||
|
);
|
||
|
|
||
|
SetVelocityDecayRate( 110 );
|
||
|
}
|
||
|
|
||
|
|
||
|
bool CWalkerMiniStrider::IsPassengerVisible( int nRole )
|
||
|
{
|
||
|
if ( nRole == VEHICLE_ROLE_DRIVER )
|
||
|
return false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::StartFiringMachineGun()
|
||
|
{
|
||
|
StopFiringLargeGun();
|
||
|
m_bFiringMachineGun = true;
|
||
|
m_flNextShootTime = gpGlobals->curtime;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::StopFiringMachineGun()
|
||
|
{
|
||
|
m_bFiringMachineGun = false;
|
||
|
}
|
||
|
|
||
|
|
||
|
Vector CWalkerMiniStrider::GetLargeGunShootOrigin()
|
||
|
{
|
||
|
Vector vRet;
|
||
|
QAngle dummyAngle;
|
||
|
if ( GetAttachment( LookupAttachment( "LargeGun" ), vRet, dummyAngle ) )
|
||
|
{
|
||
|
return vRet;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return GetAbsOrigin();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::StartFiringLargeGun()
|
||
|
{
|
||
|
CBasePlayer *pPlayer = GetPassenger( VEHICLE_ROLE_DRIVER );
|
||
|
Assert( pPlayer );
|
||
|
if ( !pPlayer )
|
||
|
return;
|
||
|
|
||
|
// Figure out what we're shooting at.
|
||
|
Vector vSrc = GetLargeGunShootOrigin();
|
||
|
|
||
|
Vector vEyePos = pPlayer->EyePosition();
|
||
|
Vector vEyeForward;
|
||
|
AngleVectors( pPlayer->LocalEyeAngles(), &vEyeForward );
|
||
|
|
||
|
trace_t trace;
|
||
|
UTIL_TraceLine( vEyePos, vEyePos + vEyeForward * 2000, MASK_SOLID, this, COLLISION_GROUP_NONE, &trace );
|
||
|
if ( trace.fraction < 1 )
|
||
|
{
|
||
|
m_vLargeGunForward = trace.endpos - vSrc;
|
||
|
VectorNormalize( m_vLargeGunForward );
|
||
|
|
||
|
trace_t trace;
|
||
|
UTIL_TraceLine( vSrc, vSrc + m_vLargeGunForward * 2000, MASK_SOLID, this, COLLISION_GROUP_NONE, &trace );
|
||
|
if ( trace.fraction < 1 )
|
||
|
{
|
||
|
EnableWalkMode( false );
|
||
|
|
||
|
m_vLargeGunTargetPos = trace.endpos;
|
||
|
m_flLargeGunCountdown = LARGE_GUN_FIRE_TIME;
|
||
|
m_bFiringLargeGun = true;
|
||
|
|
||
|
// Show an energy beam until we actually shoot.
|
||
|
m_pEnergyBeam = CBeam::BeamCreate( "sprites/physbeam.vmt", 25 );
|
||
|
m_pEnergyBeam->SetColor( 255, 0, 0 );
|
||
|
m_pEnergyBeam->SetBrightness( 100 );
|
||
|
m_pEnergyBeam->SetNoise( 4 );
|
||
|
m_pEnergyBeam->PointsInit( vSrc, m_vLargeGunTargetPos );
|
||
|
m_pEnergyBeam->LiveForTime( LARGE_GUN_FIRE_TIME );
|
||
|
|
||
|
// Play a charge-up sound.
|
||
|
CPASAttenuationFilter filter( this, "Skirmisher.GunChargeSound" );
|
||
|
EmitSound( filter, 0, "Skirmisher.GunChargeSound", &vSrc );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::StopFiringLargeGun()
|
||
|
{
|
||
|
if ( m_bFiringLargeGun )
|
||
|
{
|
||
|
m_bFiringLargeGun = false;
|
||
|
|
||
|
UTIL_Remove( m_pEnergyBeam );
|
||
|
m_pEnergyBeam = NULL;
|
||
|
|
||
|
EnableWalkMode( true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::UpdateLargeGun()
|
||
|
{
|
||
|
float dt = GetTimeDelta();
|
||
|
|
||
|
if ( !m_bFiringLargeGun )
|
||
|
return;
|
||
|
|
||
|
m_flLargeGunCountdown -= dt;
|
||
|
if ( m_flLargeGunCountdown <= 0 )
|
||
|
{
|
||
|
// Fire!
|
||
|
Vector vSrc = GetLargeGunShootOrigin();
|
||
|
trace_t trace;
|
||
|
UTIL_TraceLine( vSrc, vSrc + m_vLargeGunForward * 2000, MASK_SOLID, this, COLLISION_GROUP_NONE, &trace );
|
||
|
if ( trace.fraction < 1 )
|
||
|
{
|
||
|
CBasePlayer *pDriver = GetPassenger( VEHICLE_ROLE_DRIVER );
|
||
|
if ( pDriver )
|
||
|
{
|
||
|
UTIL_ImpactTrace( &trace, DMG_ENERGYBEAM, "Strider" );
|
||
|
|
||
|
Vector vHitPos = trace.endpos;
|
||
|
float flDamageRadius = 100;
|
||
|
float flDamage = 100;
|
||
|
|
||
|
CPASFilter filter( vHitPos );
|
||
|
te->Explosion( filter, 0.0,
|
||
|
&vHitPos,
|
||
|
g_sModelIndexFireball,
|
||
|
2.0,
|
||
|
15,
|
||
|
TE_EXPLFLAG_NONE,
|
||
|
flDamageRadius,
|
||
|
flDamage );
|
||
|
|
||
|
UTIL_ScreenShake( vHitPos, 10.0, 150.0, 1.0, 100, SHAKE_START );
|
||
|
RadiusDamage( CTakeDamageInfo( this, pDriver, flDamage, DMG_BLAST ), vHitPos, flDamageRadius, CLASS_NONE, NULL );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
StopFiringLargeGun();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::Crouch()
|
||
|
{
|
||
|
if ( m_State == STATE_CROUCHING || m_State == STATE_CROUCHED )
|
||
|
return;
|
||
|
|
||
|
// Disable the base class's walking functionality while we're crouched.
|
||
|
EnableWalkMode( false );
|
||
|
|
||
|
SetActivity( ACT_CROUCH );
|
||
|
m_flCrouchTimer = SequenceDuration();
|
||
|
m_State = STATE_CROUCHING;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::UnCrouch()
|
||
|
{
|
||
|
if ( m_State == STATE_CROUCHING || m_State == STATE_UNCROUCHING || m_State == STATE_NORMAL )
|
||
|
return;
|
||
|
|
||
|
SetActivity( ACT_STAND );
|
||
|
|
||
|
m_flCrouchTimer = SequenceDuration();
|
||
|
|
||
|
m_State = STATE_UNCROUCHING;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::UpdateCrouch()
|
||
|
{
|
||
|
float dt = GetTimeDelta();
|
||
|
|
||
|
m_flCrouchTimer -= dt;
|
||
|
if ( m_flCrouchTimer <= 0 )
|
||
|
{
|
||
|
if ( m_State == STATE_CROUCHING )
|
||
|
{
|
||
|
m_State = STATE_CROUCHED;
|
||
|
SetActivity( ACT_CROUCHIDLE );
|
||
|
}
|
||
|
else if ( m_State == STATE_UNCROUCHING )
|
||
|
{
|
||
|
EnableWalkMode( true );
|
||
|
m_State = STATE_NORMAL;
|
||
|
SetActivity( ACT_IDLE );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::FireMachineGun()
|
||
|
{
|
||
|
CBaseEntity *pDriver = GetPassenger( VEHICLE_ROLE_DRIVER );
|
||
|
if ( pDriver )
|
||
|
{
|
||
|
// Alternate the gun we're firing
|
||
|
char *attachmentNames[2] = { "MachineGun_Left", "MachineGun_Right" };
|
||
|
int iAttachment = LookupAttachment( attachmentNames[!m_bFiringLeftGun] );
|
||
|
m_bFiringLeftGun = !m_bFiringLeftGun;
|
||
|
|
||
|
Vector vAttachmentPos;
|
||
|
QAngle vAttachmentAngles;
|
||
|
GetAttachment( iAttachment, vAttachmentPos, vAttachmentAngles );
|
||
|
|
||
|
Vector vEyePos = pDriver->EyePosition();
|
||
|
Vector vEyeForward;
|
||
|
QAngle vecAngles = pDriver->LocalEyeAngles();
|
||
|
// Use the skirmisher's yaw
|
||
|
vecAngles[YAW] = GetAbsAngles()[YAW];
|
||
|
AngleVectors( vecAngles, &vEyeForward );
|
||
|
|
||
|
// Trace ahead to find out where the crosshair is aiming
|
||
|
trace_t trace;
|
||
|
float flMaxRange = tf_skirmisher_machinegun_range.GetFloat();
|
||
|
UTIL_TraceLine(
|
||
|
vEyePos,
|
||
|
vEyePos + vEyeForward * flMaxRange,
|
||
|
MASK_SOLID,
|
||
|
this,
|
||
|
COLLISION_GROUP_NONE,
|
||
|
&trace );
|
||
|
|
||
|
Vector vecDir;
|
||
|
if ( trace.fraction < 1.0 )
|
||
|
{
|
||
|
vecDir = (trace.endpos - vAttachmentPos );
|
||
|
VectorNormalize( vecDir );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
vecDir = vEyeForward;
|
||
|
}
|
||
|
|
||
|
// Shoot!
|
||
|
TFGameRules()->FireBullets( CTakeDamageInfo( this, pDriver, tf_skirmisher_machinegun_damage.GetFloat(), DMG_BULLET ),
|
||
|
1, // Num shots
|
||
|
vAttachmentPos,
|
||
|
vecDir,
|
||
|
VECTOR_CONE_3DEGREES, // Spread
|
||
|
flMaxRange, // Range
|
||
|
DMG_BULLET,
|
||
|
1, // Tracer freq
|
||
|
entindex(),
|
||
|
iAttachment, // Attachment ID
|
||
|
"MinigunTracer" );
|
||
|
|
||
|
m_flNextShootTime += (1.0f / tf_skirmisher_machinegun_rof.GetFloat());
|
||
|
|
||
|
// Play the fire sound.
|
||
|
Vector vCenter = WorldSpaceCenter();
|
||
|
CPASAttenuationFilter filter( this, "Skirmisher.GunSound" );
|
||
|
EmitSound( filter, 0, "Skirmisher.GunSound", &vCenter );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::WalkerThink()
|
||
|
{
|
||
|
float dt = GetTimeDelta();
|
||
|
|
||
|
BaseClass::WalkerThink();
|
||
|
|
||
|
// Shoot the machine gun?
|
||
|
if ( !m_bFiringLargeGun )
|
||
|
{
|
||
|
if ( m_LastButtons & IN_ATTACK )
|
||
|
{
|
||
|
if ( !m_bFiringMachineGun )
|
||
|
StartFiringMachineGun();
|
||
|
}
|
||
|
else if ( m_bFiringMachineGun )
|
||
|
{
|
||
|
StopFiringMachineGun();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Fire the large gun?
|
||
|
if ( !m_bFiringMachineGun )
|
||
|
{
|
||
|
if ( m_LastButtons & IN_ATTACK2 )
|
||
|
{
|
||
|
if ( !m_bFiringLargeGun )
|
||
|
StartFiringLargeGun();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
UpdateCrouch();
|
||
|
|
||
|
// Make sure it's crouched when there is no driver.
|
||
|
if ( GetPassenger( VEHICLE_ROLE_DRIVER ) )
|
||
|
{
|
||
|
if ( m_LastButtons & IN_DUCK )
|
||
|
{
|
||
|
Crouch();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UnCrouch();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Crouch();
|
||
|
}
|
||
|
|
||
|
if ( m_bFiringMachineGun )
|
||
|
{
|
||
|
while ( gpGlobals->curtime > m_flNextShootTime )
|
||
|
{
|
||
|
FireMachineGun();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
UpdateLargeGun();
|
||
|
|
||
|
// Move our torso within range of our feet.
|
||
|
if ( m_flOriginToLowestLegHeight != -1 )
|
||
|
{
|
||
|
Vector vCenter = WorldSpaceCenter();
|
||
|
|
||
|
//NDebugOverlay::EntityBounds( this, 255, 100, 0, 0 ,0 );
|
||
|
//NDebugOverlay::Line( vCenter, vCenter-Vector(0,0,2000), 255,0,0, true, 0 );
|
||
|
|
||
|
trace_t trace;
|
||
|
UTIL_TraceLine(
|
||
|
vCenter,
|
||
|
vCenter - 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 = vCenter;
|
||
|
vCur.z = Approach( m_flWantedZ, vCur.z, STRIDER_TORSO_VERTICAL_SLIDE_SPEED * dt );
|
||
|
SetAbsOrigin( GetAbsOrigin() + Vector( 0, 0, vCur.z - vCenter.z ) );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::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 CWalkerMiniStrider::SetupMove( CBasePlayer *pPlayer, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
|
||
|
{
|
||
|
BaseClass::SetupMove( pPlayer, ucmd, pHelper, move );
|
||
|
}
|
||
|
|
||
|
|
||
|
bool CWalkerMiniStrider::StartBuilding( CBaseEntity *pBuilder )
|
||
|
{
|
||
|
return BaseClass::StartBuilding( pBuilder );
|
||
|
}
|
||
|
|
||
|
|
||
|
Vector CWalkerMiniStrider::GetWalkerLocalMovement()
|
||
|
{
|
||
|
float dt = GetTimeDelta();
|
||
|
|
||
|
Vector vForward, vRight;
|
||
|
AngleVectors( GetLocalAngles(), &vForward, &vRight, NULL );
|
||
|
|
||
|
float flSpeed = (tf_skirmisher_speed.GetFloat() / 100) * dt;
|
||
|
Vector vMovement =
|
||
|
vForward * (GetSteerVelocity().x * flSpeed) +
|
||
|
vRight * (GetSteerVelocity().y * flSpeed);
|
||
|
|
||
|
return GetLocalOrigin() + vMovement;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::SetPassenger( int nRole, CBasePlayer *pPassenger )
|
||
|
{
|
||
|
BaseClass::SetPassenger( nRole, pPassenger );
|
||
|
|
||
|
if ( nRole == VEHICLE_ROLE_DRIVER && pPassenger )
|
||
|
UnCrouch();
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::FootHit( const char *pFootName )
|
||
|
{
|
||
|
if ( gpGlobals->curtime >= m_flNextFootstepSoundTime )
|
||
|
{
|
||
|
Vector footPosition;
|
||
|
QAngle angles;
|
||
|
|
||
|
((BaseClass*)this)->GetAttachment( pFootName, footPosition, angles );
|
||
|
CPASAttenuationFilter filter( this, "Skirmisher.Footstep" );
|
||
|
EmitSound( filter, entindex(), "Skirmisher.Footstep", &footPosition );
|
||
|
|
||
|
m_flNextFootstepSoundTime = gpGlobals->curtime + 0.2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWalkerMiniStrider::HandleAnimEvent( animevent_t *pEvent )
|
||
|
{
|
||
|
switch( pEvent->event )
|
||
|
{
|
||
|
case 1:
|
||
|
case 2:
|
||
|
case 3:
|
||
|
{
|
||
|
FootHit( "back foot" );
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|