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.
 
 
 
 
 
 

515 lines
11 KiB

//========= 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;
}
}