mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-11 19:29:08 +00:00
1
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,172 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef HL2MP_GAMERULES_H
|
||||
#define HL2MP_GAMERULES_H
|
||||
#pragma once
|
||||
|
||||
#include "gamerules.h"
|
||||
#include "teamplay_gamerules.h"
|
||||
#include "gamevars_shared.h"
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
#include "hl2mp_player.h"
|
||||
#endif
|
||||
|
||||
#define VEC_CROUCH_TRACE_MIN HL2MPRules()->GetHL2MPViewVectors()->m_vCrouchTraceMin
|
||||
#define VEC_CROUCH_TRACE_MAX HL2MPRules()->GetHL2MPViewVectors()->m_vCrouchTraceMax
|
||||
|
||||
enum
|
||||
{
|
||||
TEAM_COMBINE = 2,
|
||||
TEAM_REBELS,
|
||||
};
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CHL2MPRules C_HL2MPRules
|
||||
#define CHL2MPGameRulesProxy C_HL2MPGameRulesProxy
|
||||
#endif
|
||||
|
||||
class CHL2MPGameRulesProxy : public CGameRulesProxy
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CHL2MPGameRulesProxy, CGameRulesProxy );
|
||||
DECLARE_NETWORKCLASS();
|
||||
};
|
||||
|
||||
class HL2MPViewVectors : public CViewVectors
|
||||
{
|
||||
public:
|
||||
HL2MPViewVectors(
|
||||
Vector vView,
|
||||
Vector vHullMin,
|
||||
Vector vHullMax,
|
||||
Vector vDuckHullMin,
|
||||
Vector vDuckHullMax,
|
||||
Vector vDuckView,
|
||||
Vector vObsHullMin,
|
||||
Vector vObsHullMax,
|
||||
Vector vDeadViewHeight,
|
||||
Vector vCrouchTraceMin,
|
||||
Vector vCrouchTraceMax ) :
|
||||
CViewVectors(
|
||||
vView,
|
||||
vHullMin,
|
||||
vHullMax,
|
||||
vDuckHullMin,
|
||||
vDuckHullMax,
|
||||
vDuckView,
|
||||
vObsHullMin,
|
||||
vObsHullMax,
|
||||
vDeadViewHeight )
|
||||
{
|
||||
m_vCrouchTraceMin = vCrouchTraceMin;
|
||||
m_vCrouchTraceMax = vCrouchTraceMax;
|
||||
}
|
||||
|
||||
Vector m_vCrouchTraceMin;
|
||||
Vector m_vCrouchTraceMax;
|
||||
};
|
||||
|
||||
class CHL2MPRules : public CTeamplayRules
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CHL2MPRules, CTeamplayRules );
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
DECLARE_CLIENTCLASS_NOBASE(); // This makes datatables able to access our private vars.
|
||||
|
||||
#else
|
||||
|
||||
DECLARE_SERVERCLASS_NOBASE(); // This makes datatables able to access our private vars.
|
||||
#endif
|
||||
|
||||
CHL2MPRules();
|
||||
virtual ~CHL2MPRules();
|
||||
|
||||
virtual void Precache( void );
|
||||
virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 );
|
||||
virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args );
|
||||
|
||||
virtual float FlWeaponRespawnTime( CBaseCombatWeapon *pWeapon );
|
||||
virtual float FlWeaponTryRespawn( CBaseCombatWeapon *pWeapon );
|
||||
virtual Vector VecWeaponRespawnSpot( CBaseCombatWeapon *pWeapon );
|
||||
virtual int WeaponShouldRespawn( CBaseCombatWeapon *pWeapon );
|
||||
virtual void Think( void );
|
||||
virtual void CreateStandardEntities( void );
|
||||
virtual void ClientSettingsChanged( CBasePlayer *pPlayer );
|
||||
virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget );
|
||||
virtual void GoToIntermission( void );
|
||||
virtual void DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info );
|
||||
virtual const char *GetGameDescription( void );
|
||||
// derive this function if you mod uses encrypted weapon info files
|
||||
virtual const unsigned char *GetEncryptionKey( void ) { return (unsigned char *)"x9Ke0BY7"; }
|
||||
virtual const CViewVectors* GetViewVectors() const;
|
||||
const HL2MPViewVectors* GetHL2MPViewVectors() const;
|
||||
|
||||
float GetMapRemainingTime();
|
||||
void CleanUpMap();
|
||||
void CheckRestartGame();
|
||||
void RestartGame();
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
virtual Vector VecItemRespawnSpot( CItem *pItem );
|
||||
virtual QAngle VecItemRespawnAngles( CItem *pItem );
|
||||
virtual float FlItemRespawnTime( CItem *pItem );
|
||||
virtual bool CanHavePlayerItem( CBasePlayer *pPlayer, CBaseCombatWeapon *pItem );
|
||||
virtual bool FShouldSwitchWeapon( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon );
|
||||
|
||||
void AddLevelDesignerPlacedObject( CBaseEntity *pEntity );
|
||||
void RemoveLevelDesignerPlacedObject( CBaseEntity *pEntity );
|
||||
void ManageObjectRelocation( void );
|
||||
void CheckChatForReadySignal( CHL2MP_Player *pPlayer, const char *chatmsg );
|
||||
const char *GetChatFormat( bool bTeamOnly, CBasePlayer *pPlayer );
|
||||
|
||||
#endif
|
||||
virtual void ClientDisconnected( edict_t *pClient );
|
||||
|
||||
bool CheckGameOver( void );
|
||||
bool IsIntermission( void );
|
||||
|
||||
void PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info );
|
||||
|
||||
|
||||
bool IsTeamplay( void ) { return m_bTeamPlayEnabled; }
|
||||
void CheckAllPlayersReady( void );
|
||||
|
||||
virtual bool IsConnectedUserInfoChangeAllowed( CBasePlayer *pPlayer );
|
||||
|
||||
private:
|
||||
|
||||
CNetworkVar( bool, m_bTeamPlayEnabled );
|
||||
CNetworkVar( float, m_flGameStartTime );
|
||||
CUtlVector<EHANDLE> m_hRespawnableItemsAndWeapons;
|
||||
float m_tmNextPeriodicThink;
|
||||
float m_flRestartGameTime;
|
||||
bool m_bCompleteReset;
|
||||
bool m_bAwaitingReadyRestart;
|
||||
bool m_bHeardAllPlayersReady;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
bool m_bChangelevelDone;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline CHL2MPRules* HL2MPRules()
|
||||
{
|
||||
return static_cast<CHL2MPRules*>(g_pGameRules);
|
||||
}
|
||||
|
||||
#endif //HL2MP_GAMERULES_H
|
||||
@@ -0,0 +1,577 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "prediction.h"
|
||||
#define CRecipientFilter C_RecipientFilter
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#endif
|
||||
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "SoundEmitterSystem/isoundemittersystembase.h"
|
||||
|
||||
extern ConVar sv_footsteps;
|
||||
|
||||
const char *g_ppszPlayerSoundPrefixNames[PLAYER_SOUNDS_MAX] =
|
||||
{
|
||||
"NPC_Citizen",
|
||||
"NPC_CombineS",
|
||||
"NPC_MetroPolice",
|
||||
};
|
||||
|
||||
const char *CHL2MP_Player::GetPlayerModelSoundPrefix( void )
|
||||
{
|
||||
return g_ppszPlayerSoundPrefixNames[m_iPlayerSoundType];
|
||||
}
|
||||
|
||||
void CHL2MP_Player::PrecacheFootStepSounds( void )
|
||||
{
|
||||
int iFootstepSounds = ARRAYSIZE( g_ppszPlayerSoundPrefixNames );
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < iFootstepSounds; ++i )
|
||||
{
|
||||
char szFootStepName[128];
|
||||
|
||||
Q_snprintf( szFootStepName, sizeof( szFootStepName ), "%s.RunFootstepLeft", g_ppszPlayerSoundPrefixNames[i] );
|
||||
PrecacheScriptSound( szFootStepName );
|
||||
|
||||
Q_snprintf( szFootStepName, sizeof( szFootStepName ), "%s.RunFootstepRight", g_ppszPlayerSoundPrefixNames[i] );
|
||||
PrecacheScriptSound( szFootStepName );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Consider the weapon's built-in accuracy, this character's proficiency with
|
||||
// the weapon, and the status of the target. Use this information to determine
|
||||
// how accurately to shoot at the target.
|
||||
//-----------------------------------------------------------------------------
|
||||
Vector CHL2MP_Player::GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget )
|
||||
{
|
||||
if ( pWeapon )
|
||||
return pWeapon->GetBulletSpread( WEAPON_PROFICIENCY_PERFECT );
|
||||
|
||||
return VECTOR_CONE_15DEGREES;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : step -
|
||||
// fvol -
|
||||
// force - force sound to play
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHL2MP_Player::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force )
|
||||
{
|
||||
if ( gpGlobals->maxClients > 1 && !sv_footsteps.GetFloat() )
|
||||
return;
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
// during prediction play footstep sounds only once
|
||||
if ( !prediction->IsFirstTimePredicted() )
|
||||
return;
|
||||
#endif
|
||||
|
||||
if ( GetFlags() & FL_DUCKING )
|
||||
return;
|
||||
|
||||
m_Local.m_nStepside = !m_Local.m_nStepside;
|
||||
|
||||
char szStepSound[128];
|
||||
|
||||
if ( m_Local.m_nStepside )
|
||||
{
|
||||
Q_snprintf( szStepSound, sizeof( szStepSound ), "%s.RunFootstepLeft", g_ppszPlayerSoundPrefixNames[m_iPlayerSoundType] );
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_snprintf( szStepSound, sizeof( szStepSound ), "%s.RunFootstepRight", g_ppszPlayerSoundPrefixNames[m_iPlayerSoundType] );
|
||||
}
|
||||
|
||||
CSoundParameters params;
|
||||
if ( GetParametersForSound( szStepSound, params, NULL ) == false )
|
||||
return;
|
||||
|
||||
CRecipientFilter filter;
|
||||
filter.AddRecipientsByPAS( vecOrigin );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// im MP, server removed all players in origins PVS, these players
|
||||
// generate the footsteps clientside
|
||||
if ( gpGlobals->maxClients > 1 )
|
||||
filter.RemoveRecipientsByPVS( vecOrigin );
|
||||
#endif
|
||||
|
||||
EmitSound_t ep;
|
||||
ep.m_nChannel = CHAN_BODY;
|
||||
ep.m_pSoundName = params.soundname;
|
||||
ep.m_flVolume = fvol;
|
||||
ep.m_SoundLevel = params.soundlevel;
|
||||
ep.m_nFlags = 0;
|
||||
ep.m_nPitch = params.pitch;
|
||||
ep.m_pOrigin = &vecOrigin;
|
||||
|
||||
EmitSound( filter, entindex(), ep );
|
||||
}
|
||||
|
||||
|
||||
//==========================
|
||||
// ANIMATION CODE
|
||||
//==========================
|
||||
|
||||
|
||||
// Below this many degrees, slow down turning rate linearly
|
||||
#define FADE_TURN_DEGREES 45.0f
|
||||
// After this, need to start turning feet
|
||||
#define MAX_TORSO_ANGLE 90.0f
|
||||
// Below this amount, don't play a turning animation/perform IK
|
||||
#define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION 15.0f
|
||||
|
||||
static ConVar tf2_feetyawrunscale( "tf2_feetyawrunscale", "2", FCVAR_REPLICATED, "Multiplier on tf2_feetyawrate to allow turning faster when running." );
|
||||
extern ConVar sv_backspeed;
|
||||
extern ConVar mp_feetyawrate;
|
||||
extern ConVar mp_facefronttime;
|
||||
extern ConVar mp_ik;
|
||||
|
||||
CPlayerAnimState::CPlayerAnimState( CHL2MP_Player *outer )
|
||||
: m_pOuter( outer )
|
||||
{
|
||||
m_flGaitYaw = 0.0f;
|
||||
m_flGoalFeetYaw = 0.0f;
|
||||
m_flCurrentFeetYaw = 0.0f;
|
||||
m_flCurrentTorsoYaw = 0.0f;
|
||||
m_flLastYaw = 0.0f;
|
||||
m_flLastTurnTime = 0.0f;
|
||||
m_flTurnCorrectionTime = 0.0f;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerAnimState::Update()
|
||||
{
|
||||
m_angRender = GetOuter()->GetLocalAngles();
|
||||
m_angRender[ PITCH ] = m_angRender[ ROLL ] = 0.0f;
|
||||
|
||||
ComputePoseParam_BodyYaw();
|
||||
ComputePoseParam_BodyPitch(GetOuter()->GetModelPtr());
|
||||
ComputePoseParam_BodyLookYaw();
|
||||
|
||||
ComputePlaybackRate();
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
GetOuter()->UpdateLookAt();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerAnimState::ComputePlaybackRate()
|
||||
{
|
||||
// Determine ideal playback rate
|
||||
Vector vel;
|
||||
GetOuterAbsVelocity( vel );
|
||||
|
||||
float speed = vel.Length2D();
|
||||
|
||||
bool isMoving = ( speed > 0.5f ) ? true : false;
|
||||
|
||||
float maxspeed = GetOuter()->GetSequenceGroundSpeed( GetOuter()->GetSequence() );
|
||||
|
||||
if ( isMoving && ( maxspeed > 0.0f ) )
|
||||
{
|
||||
float flFactor = 1.0f;
|
||||
|
||||
// Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below
|
||||
GetOuter()->SetPlaybackRate( ( speed * flFactor ) / maxspeed );
|
||||
|
||||
// BUG BUG:
|
||||
// This stuff really should be m_flPlaybackRate = speed / m_flGroundSpeed
|
||||
}
|
||||
else
|
||||
{
|
||||
GetOuter()->SetPlaybackRate( 1.0f );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : CBasePlayer
|
||||
//-----------------------------------------------------------------------------
|
||||
CHL2MP_Player *CPlayerAnimState::GetOuter()
|
||||
{
|
||||
return m_pOuter;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : dt -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerAnimState::EstimateYaw( void )
|
||||
{
|
||||
float dt = gpGlobals->frametime;
|
||||
|
||||
if ( !dt )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector est_velocity;
|
||||
QAngle angles;
|
||||
|
||||
GetOuterAbsVelocity( est_velocity );
|
||||
|
||||
angles = GetOuter()->GetLocalAngles();
|
||||
|
||||
if ( est_velocity[1] == 0 && est_velocity[0] == 0 )
|
||||
{
|
||||
float flYawDiff = angles[YAW] - m_flGaitYaw;
|
||||
flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360;
|
||||
if (flYawDiff > 180)
|
||||
flYawDiff -= 360;
|
||||
if (flYawDiff < -180)
|
||||
flYawDiff += 360;
|
||||
|
||||
if (dt < 0.25)
|
||||
flYawDiff *= dt * 4;
|
||||
else
|
||||
flYawDiff *= dt;
|
||||
|
||||
m_flGaitYaw += flYawDiff;
|
||||
m_flGaitYaw = m_flGaitYaw - (int)(m_flGaitYaw / 360) * 360;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_flGaitYaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI);
|
||||
|
||||
if (m_flGaitYaw > 180)
|
||||
m_flGaitYaw = 180;
|
||||
else if (m_flGaitYaw < -180)
|
||||
m_flGaitYaw = -180;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Override for backpeddling
|
||||
// Input : dt -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerAnimState::ComputePoseParam_BodyYaw( void )
|
||||
{
|
||||
int iYaw = GetOuter()->LookupPoseParameter( "move_yaw" );
|
||||
if ( iYaw < 0 )
|
||||
return;
|
||||
|
||||
// view direction relative to movement
|
||||
float flYaw;
|
||||
|
||||
EstimateYaw();
|
||||
|
||||
QAngle angles = GetOuter()->GetLocalAngles();
|
||||
float ang = angles[ YAW ];
|
||||
if ( ang > 180.0f )
|
||||
{
|
||||
ang -= 360.0f;
|
||||
}
|
||||
else if ( ang < -180.0f )
|
||||
{
|
||||
ang += 360.0f;
|
||||
}
|
||||
|
||||
// calc side to side turning
|
||||
flYaw = ang - m_flGaitYaw;
|
||||
// Invert for mapping into 8way blend
|
||||
flYaw = -flYaw;
|
||||
flYaw = flYaw - (int)(flYaw / 360) * 360;
|
||||
|
||||
if (flYaw < -180)
|
||||
{
|
||||
flYaw = flYaw + 360;
|
||||
}
|
||||
else if (flYaw > 180)
|
||||
{
|
||||
flYaw = flYaw - 360;
|
||||
}
|
||||
|
||||
GetOuter()->SetPoseParameter( iYaw, flYaw );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
//Adrian: Make the model's angle match the legs so the hitboxes match on both sides.
|
||||
GetOuter()->SetLocalAngles( QAngle( GetOuter()->GetAnimEyeAngles().x, m_flCurrentFeetYaw, 0 ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr )
|
||||
{
|
||||
// Get pitch from v_angle
|
||||
float flPitch = GetOuter()->GetLocalAngles()[ PITCH ];
|
||||
|
||||
if ( flPitch > 180.0f )
|
||||
{
|
||||
flPitch -= 360.0f;
|
||||
}
|
||||
flPitch = clamp( flPitch, -90, 90 );
|
||||
|
||||
QAngle absangles = GetOuter()->GetAbsAngles();
|
||||
absangles.x = 0.0f;
|
||||
m_angRender = absangles;
|
||||
m_angRender[ PITCH ] = m_angRender[ ROLL ] = 0.0f;
|
||||
|
||||
// See if we have a blender for pitch
|
||||
GetOuter()->SetPoseParameter( pStudioHdr, "aim_pitch", flPitch );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : goal -
|
||||
// maxrate -
|
||||
// dt -
|
||||
// current -
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPlayerAnimState::ConvergeAngles( float goal,float maxrate, float dt, float& current )
|
||||
{
|
||||
int direction = TURN_NONE;
|
||||
|
||||
float anglediff = goal - current;
|
||||
float anglediffabs = fabs( anglediff );
|
||||
|
||||
anglediff = AngleNormalize( anglediff );
|
||||
|
||||
float scale = 1.0f;
|
||||
if ( anglediffabs <= FADE_TURN_DEGREES )
|
||||
{
|
||||
scale = anglediffabs / FADE_TURN_DEGREES;
|
||||
// Always do at least a bit of the turn ( 1% )
|
||||
scale = clamp( scale, 0.01f, 1.0f );
|
||||
}
|
||||
|
||||
float maxmove = maxrate * dt * scale;
|
||||
|
||||
if ( fabs( anglediff ) < maxmove )
|
||||
{
|
||||
current = goal;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( anglediff > 0 )
|
||||
{
|
||||
current += maxmove;
|
||||
direction = TURN_LEFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
current -= maxmove;
|
||||
direction = TURN_RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
current = AngleNormalize( current );
|
||||
|
||||
return direction;
|
||||
}
|
||||
|
||||
void CPlayerAnimState::ComputePoseParam_BodyLookYaw( void )
|
||||
{
|
||||
QAngle absangles = GetOuter()->GetAbsAngles();
|
||||
absangles.y = AngleNormalize( absangles.y );
|
||||
m_angRender = absangles;
|
||||
m_angRender[ PITCH ] = m_angRender[ ROLL ] = 0.0f;
|
||||
|
||||
// See if we even have a blender for pitch
|
||||
int upper_body_yaw = GetOuter()->LookupPoseParameter( "aim_yaw" );
|
||||
if ( upper_body_yaw < 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Assume upper and lower bodies are aligned and that we're not turning
|
||||
float flGoalTorsoYaw = 0.0f;
|
||||
int turning = TURN_NONE;
|
||||
float turnrate = 360.0f;
|
||||
|
||||
Vector vel;
|
||||
|
||||
GetOuterAbsVelocity( vel );
|
||||
|
||||
bool isMoving = ( vel.Length() > 1.0f ) ? true : false;
|
||||
|
||||
if ( !isMoving )
|
||||
{
|
||||
// Just stopped moving, try and clamp feet
|
||||
if ( m_flLastTurnTime <= 0.0f )
|
||||
{
|
||||
m_flLastTurnTime = gpGlobals->curtime;
|
||||
m_flLastYaw = GetOuter()->GetAnimEyeAngles().y;
|
||||
// Snap feet to be perfectly aligned with torso/eyes
|
||||
m_flGoalFeetYaw = GetOuter()->GetAnimEyeAngles().y;
|
||||
m_flCurrentFeetYaw = m_flGoalFeetYaw;
|
||||
m_nTurningInPlace = TURN_NONE;
|
||||
}
|
||||
|
||||
// If rotating in place, update stasis timer
|
||||
if ( m_flLastYaw != GetOuter()->GetAnimEyeAngles().y )
|
||||
{
|
||||
m_flLastTurnTime = gpGlobals->curtime;
|
||||
m_flLastYaw = GetOuter()->GetAnimEyeAngles().y;
|
||||
}
|
||||
|
||||
if ( m_flGoalFeetYaw != m_flCurrentFeetYaw )
|
||||
{
|
||||
m_flLastTurnTime = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );
|
||||
|
||||
QAngle eyeAngles = GetOuter()->GetAnimEyeAngles();
|
||||
QAngle vAngle = GetOuter()->GetLocalAngles();
|
||||
|
||||
// See how far off current feetyaw is from true yaw
|
||||
float yawdelta = GetOuter()->GetAnimEyeAngles().y - m_flCurrentFeetYaw;
|
||||
yawdelta = AngleNormalize( yawdelta );
|
||||
|
||||
bool rotated_too_far = false;
|
||||
|
||||
float yawmagnitude = fabs( yawdelta );
|
||||
|
||||
// If too far, then need to turn in place
|
||||
if ( yawmagnitude > 45 )
|
||||
{
|
||||
rotated_too_far = true;
|
||||
}
|
||||
|
||||
// Standing still for a while, rotate feet around to face forward
|
||||
// Or rotated too far
|
||||
// FIXME: Play an in place turning animation
|
||||
if ( rotated_too_far ||
|
||||
( gpGlobals->curtime > m_flLastTurnTime + mp_facefronttime.GetFloat() ) )
|
||||
{
|
||||
m_flGoalFeetYaw = GetOuter()->GetAnimEyeAngles().y;
|
||||
m_flLastTurnTime = gpGlobals->curtime;
|
||||
|
||||
/* float yd = m_flCurrentFeetYaw - m_flGoalFeetYaw;
|
||||
if ( yd > 0 )
|
||||
{
|
||||
m_nTurningInPlace = TURN_RIGHT;
|
||||
}
|
||||
else if ( yd < 0 )
|
||||
{
|
||||
m_nTurningInPlace = TURN_LEFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nTurningInPlace = TURN_NONE;
|
||||
}
|
||||
|
||||
turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );
|
||||
yawdelta = GetOuter()->GetAnimEyeAngles().y - m_flCurrentFeetYaw;*/
|
||||
|
||||
}
|
||||
|
||||
// Snap upper body into position since the delta is already smoothed for the feet
|
||||
flGoalTorsoYaw = yawdelta;
|
||||
m_flCurrentTorsoYaw = flGoalTorsoYaw;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_flLastTurnTime = 0.0f;
|
||||
m_nTurningInPlace = TURN_NONE;
|
||||
m_flCurrentFeetYaw = m_flGoalFeetYaw = GetOuter()->GetAnimEyeAngles().y;
|
||||
flGoalTorsoYaw = 0.0f;
|
||||
m_flCurrentTorsoYaw = GetOuter()->GetAnimEyeAngles().y - m_flCurrentFeetYaw;
|
||||
}
|
||||
|
||||
|
||||
if ( turning == TURN_NONE )
|
||||
{
|
||||
m_nTurningInPlace = turning;
|
||||
}
|
||||
|
||||
if ( m_nTurningInPlace != TURN_NONE )
|
||||
{
|
||||
// If we're close to finishing the turn, then turn off the turning animation
|
||||
if ( fabs( m_flCurrentFeetYaw - m_flGoalFeetYaw ) < MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION )
|
||||
{
|
||||
m_nTurningInPlace = TURN_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// Rotate entire body into position
|
||||
absangles = GetOuter()->GetAbsAngles();
|
||||
absangles.y = m_flCurrentFeetYaw;
|
||||
m_angRender = absangles;
|
||||
m_angRender[ PITCH ] = m_angRender[ ROLL ] = 0.0f;
|
||||
|
||||
GetOuter()->SetPoseParameter( upper_body_yaw, clamp( m_flCurrentTorsoYaw, -60.0f, 60.0f ) );
|
||||
|
||||
/*
|
||||
// FIXME: Adrian, what is this?
|
||||
int body_yaw = GetOuter()->LookupPoseParameter( "body_yaw" );
|
||||
|
||||
if ( body_yaw >= 0 )
|
||||
{
|
||||
GetOuter()->SetPoseParameter( body_yaw, 30 );
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : activity -
|
||||
// Output : Activity
|
||||
//-----------------------------------------------------------------------------
|
||||
Activity CPlayerAnimState::BodyYawTranslateActivity( Activity activity )
|
||||
{
|
||||
// Not even standing still, sigh
|
||||
if ( activity != ACT_IDLE )
|
||||
return activity;
|
||||
|
||||
// Not turning
|
||||
switch ( m_nTurningInPlace )
|
||||
{
|
||||
default:
|
||||
case TURN_NONE:
|
||||
return activity;
|
||||
/*
|
||||
case TURN_RIGHT:
|
||||
return ACT_TURNRIGHT45;
|
||||
case TURN_LEFT:
|
||||
return ACT_TURNLEFT45;
|
||||
*/
|
||||
case TURN_RIGHT:
|
||||
case TURN_LEFT:
|
||||
return mp_ik.GetBool() ? ACT_TURN : activity;
|
||||
}
|
||||
|
||||
Assert( 0 );
|
||||
return activity;
|
||||
}
|
||||
|
||||
const QAngle& CPlayerAnimState::GetRenderAngles()
|
||||
{
|
||||
return m_angRender;
|
||||
}
|
||||
|
||||
|
||||
void CPlayerAnimState::GetOuterAbsVelocity( Vector& vel )
|
||||
{
|
||||
#if defined( CLIENT_DLL )
|
||||
GetOuter()->EstimateAbsVelocity( vel );
|
||||
#else
|
||||
vel = GetOuter()->GetAbsVelocity();
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
#ifndef HL2MP_PLAYER_SHARED_H
|
||||
#define HL2MP_PLAYER_SHARED_H
|
||||
#pragma once
|
||||
|
||||
#define HL2MP_PUSHAWAY_THINK_INTERVAL (1.0f / 20.0f)
|
||||
#include "studio.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PLAYER_SOUNDS_CITIZEN = 0,
|
||||
PLAYER_SOUNDS_COMBINESOLDIER,
|
||||
PLAYER_SOUNDS_METROPOLICE,
|
||||
PLAYER_SOUNDS_MAX,
|
||||
};
|
||||
|
||||
enum HL2MPPlayerState
|
||||
{
|
||||
// Happily running around in the game.
|
||||
STATE_ACTIVE=0,
|
||||
STATE_OBSERVER_MODE, // Noclipping around, watching players, etc.
|
||||
NUM_PLAYER_STATES
|
||||
};
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CHL2MP_Player C_HL2MP_Player
|
||||
#endif
|
||||
|
||||
class CPlayerAnimState
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
TURN_NONE = 0,
|
||||
TURN_LEFT,
|
||||
TURN_RIGHT
|
||||
};
|
||||
|
||||
CPlayerAnimState( CHL2MP_Player *outer );
|
||||
|
||||
Activity BodyYawTranslateActivity( Activity activity );
|
||||
|
||||
void Update();
|
||||
|
||||
const QAngle& GetRenderAngles();
|
||||
|
||||
void GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM] );
|
||||
|
||||
CHL2MP_Player *GetOuter();
|
||||
|
||||
private:
|
||||
void GetOuterAbsVelocity( Vector& vel );
|
||||
|
||||
int ConvergeAngles( float goal,float maxrate, float dt, float& current );
|
||||
|
||||
void EstimateYaw( void );
|
||||
void ComputePoseParam_BodyYaw( void );
|
||||
void ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr );
|
||||
void ComputePoseParam_BodyLookYaw( void );
|
||||
|
||||
void ComputePlaybackRate();
|
||||
|
||||
CHL2MP_Player *m_pOuter;
|
||||
|
||||
float m_flGaitYaw;
|
||||
float m_flStoredCycle;
|
||||
|
||||
// The following variables are used for tweaking the yaw of the upper body when standing still and
|
||||
// making sure that it smoothly blends in and out once the player starts moving
|
||||
// Direction feet were facing when we stopped moving
|
||||
float m_flGoalFeetYaw;
|
||||
float m_flCurrentFeetYaw;
|
||||
|
||||
float m_flCurrentTorsoYaw;
|
||||
|
||||
// To check if they are rotating in place
|
||||
float m_flLastYaw;
|
||||
// Time when we stopped moving
|
||||
float m_flLastTurnTime;
|
||||
|
||||
// One of the above enums
|
||||
int m_nTurningInPlace;
|
||||
|
||||
QAngle m_angRender;
|
||||
|
||||
float m_flTurnCorrectionTime;
|
||||
};
|
||||
|
||||
#endif //HL2MP_PLAYER_SHARED_h
|
||||
@@ -0,0 +1,32 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include <KeyValues.h>
|
||||
#include "hl2mp_weapon_parse.h"
|
||||
#include "ammodef.h"
|
||||
|
||||
FileWeaponInfo_t* CreateWeaponInfo()
|
||||
{
|
||||
return new CHL2MPSWeaponInfo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CHL2MPSWeaponInfo::CHL2MPSWeaponInfo()
|
||||
{
|
||||
m_iPlayerDamage = 0;
|
||||
}
|
||||
|
||||
|
||||
void CHL2MPSWeaponInfo::Parse( KeyValues *pKeyValuesData, const char *szWeaponName )
|
||||
{
|
||||
BaseClass::Parse( pKeyValuesData, szWeaponName );
|
||||
|
||||
m_iPlayerDamage = pKeyValuesData->GetInt( "damage", 0 );
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef HL2MP_WEAPON_PARSE_H
|
||||
#define HL2MP_WEAPON_PARSE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "weapon_parse.h"
|
||||
#include "networkvar.h"
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
class CHL2MPSWeaponInfo : public FileWeaponInfo_t
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS_GAMEROOT( CHL2MPSWeaponInfo, FileWeaponInfo_t );
|
||||
|
||||
CHL2MPSWeaponInfo();
|
||||
|
||||
virtual void Parse( ::KeyValues *pKeyValuesData, const char *szWeaponName );
|
||||
|
||||
|
||||
public:
|
||||
|
||||
int m_iPlayerDamage;
|
||||
};
|
||||
|
||||
|
||||
#endif // HL2MP_WEAPON_PARSE_H
|
||||
@@ -0,0 +1,154 @@
|
||||
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "npcevent.h"
|
||||
#include "in_buttons.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#endif
|
||||
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CWeapon357 C_Weapon357
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CWeapon357
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class CWeapon357 : public CBaseHL2MPCombatWeapon
|
||||
{
|
||||
DECLARE_CLASS( CWeapon357, CBaseHL2MPCombatWeapon );
|
||||
public:
|
||||
|
||||
CWeapon357( void );
|
||||
|
||||
void PrimaryAttack( void );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_ACTTABLE();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
CWeapon357( const CWeapon357 & );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( Weapon357, DT_Weapon357 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeapon357, DT_Weapon357 )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeapon357 )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_357, CWeapon357 );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_357 );
|
||||
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
acttable_t CWeapon357::m_acttable[] =
|
||||
{
|
||||
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_PISTOL, false },
|
||||
{ ACT_HL2MP_RUN, ACT_HL2MP_RUN_PISTOL, false },
|
||||
{ ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_PISTOL, false },
|
||||
{ ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_PISTOL, false },
|
||||
{ ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL, false },
|
||||
{ ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PISTOL, false },
|
||||
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PISTOL, false },
|
||||
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_PISTOL, false },
|
||||
};
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_ACTTABLE( CWeapon357 );
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CWeapon357::CWeapon357( void )
|
||||
{
|
||||
m_bReloadsSingly = false;
|
||||
m_bFiresUnderwater = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeapon357::PrimaryAttack( void )
|
||||
{
|
||||
// Only the player fires this way so we can cast
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( !pPlayer )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_iClip1 <= 0 )
|
||||
{
|
||||
if ( !m_bFireOnEmpty )
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
WeaponSound( EMPTY );
|
||||
m_flNextPrimaryAttack = 0.15;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
WeaponSound( SINGLE );
|
||||
pPlayer->DoMuzzleFlash();
|
||||
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.75;
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 0.75;
|
||||
|
||||
m_iClip1--;
|
||||
|
||||
Vector vecSrc = pPlayer->Weapon_ShootPosition();
|
||||
Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
|
||||
|
||||
FireBulletsInfo_t info( 1, vecSrc, vecAiming, vec3_origin, MAX_TRACE_LENGTH, m_iPrimaryAmmoType );
|
||||
info.m_pAttacker = pPlayer;
|
||||
|
||||
// Fire the bullets, and force the first shot to be perfectly accuracy
|
||||
pPlayer->FireBullets( info );
|
||||
|
||||
//Disorient the player
|
||||
QAngle angles = pPlayer->GetLocalAngles();
|
||||
|
||||
angles.x += random->RandomInt( -1, 1 );
|
||||
angles.y += random->RandomInt( -1, 1 );
|
||||
angles.z = 0;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
pPlayer->SnapEyeAngles( angles );
|
||||
#endif
|
||||
|
||||
pPlayer->ViewPunch( QAngle( -8, random->RandomFloat( -2, 2 ), 0 ) );
|
||||
|
||||
if ( !m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
|
||||
{
|
||||
// HEV suit - indicate out of ammo condition
|
||||
pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "npcevent.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "c_te_effect_dispatch.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "te_effect_dispatch.h"
|
||||
#include "prop_combine_ball.h"
|
||||
#endif
|
||||
|
||||
#include "weapon_ar2.h"
|
||||
#include "effect_dispatch_data.h"
|
||||
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
ConVar sk_weapon_ar2_alt_fire_radius( "sk_weapon_ar2_alt_fire_radius", "10" );
|
||||
ConVar sk_weapon_ar2_alt_fire_duration( "sk_weapon_ar2_alt_fire_duration", "4" );
|
||||
ConVar sk_weapon_ar2_alt_fire_mass( "sk_weapon_ar2_alt_fire_mass", "150" );
|
||||
#endif
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponAR2, DT_WeaponAR2 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponAR2, DT_WeaponAR2 )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponAR2 )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_ar2, CWeaponAR2 );
|
||||
PRECACHE_WEAPON_REGISTER(weapon_ar2);
|
||||
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
acttable_t CWeaponAR2::m_acttable[] =
|
||||
{
|
||||
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_AR2, false },
|
||||
{ ACT_HL2MP_RUN, ACT_HL2MP_RUN_AR2, false },
|
||||
{ ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_AR2, false },
|
||||
{ ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_AR2, false },
|
||||
{ ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false },
|
||||
{ ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_AR2, false },
|
||||
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_AR2, false },
|
||||
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_AR2, false },
|
||||
};
|
||||
|
||||
IMPLEMENT_ACTTABLE(CWeaponAR2);
|
||||
|
||||
#endif
|
||||
|
||||
CWeaponAR2::CWeaponAR2( )
|
||||
{
|
||||
m_fMinRange1 = 65;
|
||||
m_fMaxRange1 = 2048;
|
||||
|
||||
m_fMinRange2 = 256;
|
||||
m_fMaxRange2 = 1024;
|
||||
|
||||
m_nShotsFired = 0;
|
||||
m_nVentPose = -1;
|
||||
}
|
||||
|
||||
void CWeaponAR2::Precache( void )
|
||||
{
|
||||
BaseClass::Precache();
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
UTIL_PrecacheOther( "prop_combine_ball" );
|
||||
UTIL_PrecacheOther( "env_entity_dissolver" );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handle grenade detonate in-air (even when no ammo is left)
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponAR2::ItemPostFrame( void )
|
||||
{
|
||||
// See if we need to fire off our secondary round
|
||||
if ( m_bShotDelayed && gpGlobals->curtime > m_flDelayedFire )
|
||||
{
|
||||
DelayedAttack();
|
||||
}
|
||||
|
||||
// Update our pose parameter for the vents
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pOwner )
|
||||
{
|
||||
CBaseViewModel *pVM = pOwner->GetViewModel();
|
||||
|
||||
if ( pVM )
|
||||
{
|
||||
if ( m_nVentPose == -1 )
|
||||
{
|
||||
m_nVentPose = pVM->LookupPoseParameter( "VentPoses" );
|
||||
}
|
||||
|
||||
float flVentPose = RemapValClamped( m_nShotsFired, 0, 5, 0.0f, 1.0f );
|
||||
pVM->SetPoseParameter( m_nVentPose, flVentPose );
|
||||
}
|
||||
}
|
||||
|
||||
BaseClass::ItemPostFrame();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Activity
|
||||
//-----------------------------------------------------------------------------
|
||||
Activity CWeaponAR2::GetPrimaryAttackActivity( void )
|
||||
{
|
||||
if ( m_nShotsFired < 2 )
|
||||
return ACT_VM_PRIMARYATTACK;
|
||||
|
||||
if ( m_nShotsFired < 3 )
|
||||
return ACT_VM_RECOIL1;
|
||||
|
||||
if ( m_nShotsFired < 4 )
|
||||
return ACT_VM_RECOIL2;
|
||||
|
||||
return ACT_VM_RECOIL3;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &tr -
|
||||
// nDamageType -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponAR2::DoImpactEffect( trace_t &tr, int nDamageType )
|
||||
{
|
||||
CEffectData data;
|
||||
|
||||
data.m_vOrigin = tr.endpos + ( tr.plane.normal * 1.0f );
|
||||
data.m_vNormal = tr.plane.normal;
|
||||
|
||||
DispatchEffect( "AR2Impact", data );
|
||||
|
||||
BaseClass::DoImpactEffect( tr, nDamageType );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponAR2::DelayedAttack( void )
|
||||
{
|
||||
m_bShotDelayed = false;
|
||||
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pOwner == NULL )
|
||||
return;
|
||||
|
||||
// Deplete the clip completely
|
||||
SendWeaponAnim( ACT_VM_SECONDARYATTACK );
|
||||
m_flNextSecondaryAttack = pOwner->m_flNextAttack = gpGlobals->curtime + SequenceDuration();
|
||||
|
||||
// Register a muzzleflash for the AI
|
||||
pOwner->DoMuzzleFlash();
|
||||
|
||||
WeaponSound( WPN_DOUBLE );
|
||||
|
||||
// Fire the bullets
|
||||
Vector vecSrc = pOwner->Weapon_ShootPosition( );
|
||||
Vector vecAiming = pOwner->GetAutoaimVector( AUTOAIM_2DEGREES );
|
||||
Vector impactPoint = vecSrc + ( vecAiming * MAX_TRACE_LENGTH );
|
||||
|
||||
// Fire the bullets
|
||||
Vector vecVelocity = vecAiming * 1000.0f;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// Fire the combine ball
|
||||
CreateCombineBall( vecSrc,
|
||||
vecVelocity,
|
||||
sk_weapon_ar2_alt_fire_radius.GetFloat(),
|
||||
sk_weapon_ar2_alt_fire_mass.GetFloat(),
|
||||
sk_weapon_ar2_alt_fire_duration.GetFloat(),
|
||||
pOwner );
|
||||
|
||||
// View effects
|
||||
color32 white = {255, 255, 255, 64};
|
||||
UTIL_ScreenFade( pOwner, white, 0.1, 0, FFADE_IN );
|
||||
#endif
|
||||
|
||||
//Disorient the player
|
||||
QAngle angles = pOwner->GetLocalAngles();
|
||||
|
||||
angles.x += random->RandomInt( -4, 4 );
|
||||
angles.y += random->RandomInt( -4, 4 );
|
||||
angles.z = 0;
|
||||
|
||||
// pOwner->SnapEyeAngles( angles );
|
||||
|
||||
pOwner->ViewPunch( QAngle( SharedRandomInt( "ar2pax", -8, -12 ), SharedRandomInt( "ar2pay", 1, 2 ), 0 ) );
|
||||
|
||||
// Decrease ammo
|
||||
pOwner->RemoveAmmo( 1, m_iSecondaryAmmoType );
|
||||
|
||||
// Can shoot again immediately
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.5f;
|
||||
|
||||
// Can blow up after a short delay (so have time to release mouse button)
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 1.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponAR2::SecondaryAttack( void )
|
||||
{
|
||||
if ( m_bShotDelayed )
|
||||
return;
|
||||
|
||||
// Cannot fire underwater
|
||||
if ( GetOwner() && GetOwner()->GetWaterLevel() == 3 )
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_DRYFIRE );
|
||||
BaseClass::WeaponSound( EMPTY );
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f;
|
||||
return;
|
||||
}
|
||||
|
||||
m_bShotDelayed = true;
|
||||
m_flNextPrimaryAttack = m_flNextSecondaryAttack = m_flDelayedFire = gpGlobals->curtime + 0.5f;
|
||||
|
||||
SendWeaponAnim( ACT_VM_FIDGET );
|
||||
WeaponSound( SPECIAL1 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Override if we're waiting to release a shot
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponAR2::CanHolster( void )
|
||||
{
|
||||
if ( m_bShotDelayed )
|
||||
return false;
|
||||
|
||||
return BaseClass::CanHolster();
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponAR2::Deploy( void )
|
||||
{
|
||||
m_bShotDelayed = false;
|
||||
m_flDelayedFire = 0.0f;
|
||||
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Override if we're waiting to release a shot
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponAR2::Reload( void )
|
||||
{
|
||||
if ( m_bShotDelayed )
|
||||
return false;
|
||||
|
||||
return BaseClass::Reload();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponAR2::AddViewKick( void )
|
||||
{
|
||||
#define EASY_DAMPEN 0.5f
|
||||
#define MAX_VERTICAL_KICK 8.0f //Degrees
|
||||
#define SLIDE_LIMIT 5.0f //Seconds
|
||||
|
||||
//Get the view kick
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
|
||||
if (!pPlayer)
|
||||
return;
|
||||
|
||||
DoMachineGunKick( pPlayer, EASY_DAMPEN, MAX_VERTICAL_KICK, m_fFireDuration, SLIDE_LIMIT );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const WeaponProficiencyInfo_t *CWeaponAR2::GetProficiencyValues()
|
||||
{
|
||||
static WeaponProficiencyInfo_t proficiencyTable[] =
|
||||
{
|
||||
{ 7.0, 0.75 },
|
||||
{ 5.00, 0.75 },
|
||||
{ 3.0, 0.85 },
|
||||
{ 5.0/3.0, 0.75 },
|
||||
{ 1.00, 1.0 },
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT( ARRAYSIZE(proficiencyTable) == WEAPON_PROFICIENCY_PERFECT + 1);
|
||||
|
||||
return proficiencyTable;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Projectile shot from the AR2
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef WEAPONAR2_H
|
||||
#define WEAPONAR2_H
|
||||
|
||||
#include "basegrenade_shared.h"
|
||||
#include "weapon_hl2mpbase_machinegun.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CWeaponAR2 C_WeaponAR2
|
||||
#endif
|
||||
|
||||
class CWeaponAR2 : public CHL2MPMachineGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponAR2, CHL2MPMachineGun );
|
||||
|
||||
CWeaponAR2();
|
||||
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
void ItemPostFrame( void );
|
||||
void Precache( void );
|
||||
|
||||
void SecondaryAttack( void );
|
||||
void DelayedAttack( void );
|
||||
|
||||
const char *GetTracerType( void ) { return "AR2Tracer"; }
|
||||
|
||||
void AddViewKick( void );
|
||||
|
||||
int GetMinBurst( void ) { return 2; }
|
||||
int GetMaxBurst( void ) { return 5; }
|
||||
float GetFireRate( void ) { return 0.1f; }
|
||||
|
||||
bool CanHolster( void );
|
||||
bool Reload( void );
|
||||
|
||||
Activity GetPrimaryAttackActivity( void );
|
||||
|
||||
void DoImpactEffect( trace_t &tr, int nDamageType );
|
||||
|
||||
virtual bool Deploy( void );
|
||||
|
||||
|
||||
virtual const Vector& GetBulletSpread( void )
|
||||
{
|
||||
static Vector cone;
|
||||
|
||||
cone = VECTOR_CONE_3DEGREES;
|
||||
|
||||
return cone;
|
||||
}
|
||||
|
||||
const WeaponProficiencyInfo_t *GetProficiencyValues();
|
||||
|
||||
private:
|
||||
CWeaponAR2( const CWeaponAR2 & );
|
||||
|
||||
protected:
|
||||
|
||||
float m_flDelayedFire;
|
||||
bool m_bShotDelayed;
|
||||
int m_nVentPose;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_ACTTABLE();
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#endif //WEAPONAR2_H
|
||||
@@ -0,0 +1,956 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "npcevent.h"
|
||||
#include "in_buttons.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "c_te_effect_dispatch.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "te_effect_dispatch.h"
|
||||
#include "IEffects.h"
|
||||
#include "Sprite.h"
|
||||
#include "SpriteTrail.h"
|
||||
#include "beam_shared.h"
|
||||
#endif
|
||||
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
#include "effect_dispatch_data.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//#define BOLT_MODEL "models/crossbow_bolt.mdl"
|
||||
#define BOLT_MODEL "models/weapons/w_missile_closed.mdl"
|
||||
|
||||
#define BOLT_AIR_VELOCITY 3500
|
||||
#define BOLT_WATER_VELOCITY 1500
|
||||
#define BOLT_SKIN_NORMAL 0
|
||||
#define BOLT_SKIN_GLOW 1
|
||||
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
extern ConVar sk_plr_dmg_crossbow;
|
||||
extern ConVar sk_npc_dmg_crossbow;
|
||||
|
||||
void TE_StickyBolt( IRecipientFilter& filter, float delay, Vector vecDirection, const Vector *origin );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Crossbow Bolt
|
||||
//-----------------------------------------------------------------------------
|
||||
class CCrossbowBolt : public CBaseCombatCharacter
|
||||
{
|
||||
DECLARE_CLASS( CCrossbowBolt, CBaseCombatCharacter );
|
||||
|
||||
public:
|
||||
CCrossbowBolt() { };
|
||||
~CCrossbowBolt();
|
||||
|
||||
Class_T Classify( void ) { return CLASS_NONE; }
|
||||
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
void BubbleThink( void );
|
||||
void BoltTouch( CBaseEntity *pOther );
|
||||
bool CreateVPhysics( void );
|
||||
unsigned int PhysicsSolidMaskForEntity() const;
|
||||
static CCrossbowBolt *BoltCreate( const Vector &vecOrigin, const QAngle &angAngles, int iDamage, CBasePlayer *pentOwner = NULL );
|
||||
|
||||
protected:
|
||||
|
||||
bool CreateSprites( void );
|
||||
|
||||
CHandle<CSprite> m_pGlowSprite;
|
||||
//CHandle<CSpriteTrail> m_pGlowTrail;
|
||||
|
||||
int m_iDamage;
|
||||
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_SERVERCLASS();
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( crossbow_bolt, CCrossbowBolt );
|
||||
|
||||
BEGIN_DATADESC( CCrossbowBolt )
|
||||
// Function Pointers
|
||||
DEFINE_FUNCTION( BubbleThink ),
|
||||
DEFINE_FUNCTION( BoltTouch ),
|
||||
|
||||
// These are recreated on reload, they don't need storage
|
||||
DEFINE_FIELD( m_pGlowSprite, FIELD_EHANDLE ),
|
||||
//DEFINE_FIELD( m_pGlowTrail, FIELD_EHANDLE ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( CCrossbowBolt, DT_CrossbowBolt )
|
||||
END_SEND_TABLE()
|
||||
|
||||
CCrossbowBolt *CCrossbowBolt::BoltCreate( const Vector &vecOrigin, const QAngle &angAngles, int iDamage, CBasePlayer *pentOwner )
|
||||
{
|
||||
// Create a new entity with CCrossbowBolt private data
|
||||
CCrossbowBolt *pBolt = (CCrossbowBolt *)CreateEntityByName( "crossbow_bolt" );
|
||||
UTIL_SetOrigin( pBolt, vecOrigin );
|
||||
pBolt->SetAbsAngles( angAngles );
|
||||
pBolt->Spawn();
|
||||
pBolt->SetOwnerEntity( pentOwner );
|
||||
|
||||
pBolt->m_iDamage = iDamage;
|
||||
|
||||
return pBolt;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CCrossbowBolt::~CCrossbowBolt( void )
|
||||
{
|
||||
if ( m_pGlowSprite )
|
||||
{
|
||||
UTIL_Remove( m_pGlowSprite );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CCrossbowBolt::CreateVPhysics( void )
|
||||
{
|
||||
// Create the object in the physics system
|
||||
VPhysicsInitNormal( SOLID_BBOX, FSOLID_NOT_STANDABLE, false );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned int CCrossbowBolt::PhysicsSolidMaskForEntity() const
|
||||
{
|
||||
return ( BaseClass::PhysicsSolidMaskForEntity() | CONTENTS_HITBOX ) & ~CONTENTS_GRATE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CCrossbowBolt::CreateSprites( void )
|
||||
{
|
||||
// Start up the eye glow
|
||||
m_pGlowSprite = CSprite::SpriteCreate( "sprites/light_glow02_noz.vmt", GetLocalOrigin(), false );
|
||||
|
||||
if ( m_pGlowSprite != NULL )
|
||||
{
|
||||
m_pGlowSprite->FollowEntity( this );
|
||||
m_pGlowSprite->SetTransparency( kRenderGlow, 255, 255, 255, 128, kRenderFxNoDissipation );
|
||||
m_pGlowSprite->SetScale( 0.2f );
|
||||
m_pGlowSprite->TurnOff();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCrossbowBolt::Spawn( void )
|
||||
{
|
||||
Precache( );
|
||||
|
||||
SetModel( "models/crossbow_bolt.mdl" );
|
||||
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM );
|
||||
UTIL_SetSize( this, -Vector(1,1,1), Vector(1,1,1) );
|
||||
SetSolid( SOLID_BBOX );
|
||||
SetGravity( 0.05f );
|
||||
|
||||
// Make sure we're updated if we're underwater
|
||||
UpdateWaterState();
|
||||
|
||||
SetTouch( &CCrossbowBolt::BoltTouch );
|
||||
|
||||
SetThink( &CCrossbowBolt::BubbleThink );
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
|
||||
CreateSprites();
|
||||
|
||||
// Make us glow until we've hit the wall
|
||||
m_nSkin = BOLT_SKIN_GLOW;
|
||||
}
|
||||
|
||||
|
||||
void CCrossbowBolt::Precache( void )
|
||||
{
|
||||
PrecacheModel( BOLT_MODEL );
|
||||
|
||||
// This is used by C_TEStickyBolt, despte being different from above!!!
|
||||
PrecacheModel( "models/crossbow_bolt.mdl" );
|
||||
|
||||
PrecacheModel( "sprites/light_glow02_noz.vmt" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pOther -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCrossbowBolt::BoltTouch( CBaseEntity *pOther )
|
||||
{
|
||||
if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) )
|
||||
return;
|
||||
|
||||
if ( pOther->m_takedamage != DAMAGE_NO )
|
||||
{
|
||||
trace_t tr, tr2;
|
||||
tr = BaseClass::GetTouchTrace();
|
||||
Vector vecNormalizedVel = GetAbsVelocity();
|
||||
|
||||
ClearMultiDamage();
|
||||
VectorNormalize( vecNormalizedVel );
|
||||
|
||||
if( GetOwnerEntity() && GetOwnerEntity()->IsPlayer() && pOther->IsNPC() )
|
||||
{
|
||||
CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_iDamage, DMG_NEVERGIB );
|
||||
dmgInfo.AdjustPlayerDamageInflictedForSkillLevel();
|
||||
CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f );
|
||||
dmgInfo.SetDamagePosition( tr.endpos );
|
||||
pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr );
|
||||
}
|
||||
else
|
||||
{
|
||||
CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_iDamage, DMG_BULLET | DMG_NEVERGIB );
|
||||
CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f );
|
||||
dmgInfo.SetDamagePosition( tr.endpos );
|
||||
pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr );
|
||||
}
|
||||
|
||||
ApplyMultiDamage();
|
||||
|
||||
//Adrian: keep going through the glass.
|
||||
if ( pOther->GetCollisionGroup() == COLLISION_GROUP_BREAKABLE_GLASS )
|
||||
return;
|
||||
|
||||
SetAbsVelocity( Vector( 0, 0, 0 ) );
|
||||
|
||||
// play body "thwack" sound
|
||||
EmitSound( "Weapon_Crossbow.BoltHitBody" );
|
||||
|
||||
Vector vForward;
|
||||
|
||||
AngleVectors( GetAbsAngles(), &vForward );
|
||||
VectorNormalize ( vForward );
|
||||
|
||||
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vForward * 128, MASK_OPAQUE, pOther, COLLISION_GROUP_NONE, &tr2 );
|
||||
|
||||
if ( tr2.fraction != 1.0f )
|
||||
{
|
||||
// NDebugOverlay::Box( tr2.endpos, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 255, 0, 0, 10 );
|
||||
// NDebugOverlay::Box( GetAbsOrigin(), Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 0, 255, 0, 10 );
|
||||
|
||||
if ( tr2.m_pEnt == NULL || ( tr2.m_pEnt && tr2.m_pEnt->GetMoveType() == MOVETYPE_NONE ) )
|
||||
{
|
||||
CEffectData data;
|
||||
|
||||
data.m_vOrigin = tr2.endpos;
|
||||
data.m_vNormal = vForward;
|
||||
data.m_nEntIndex = tr2.fraction != 1.0f;
|
||||
|
||||
DispatchEffect( "BoltImpact", data );
|
||||
}
|
||||
}
|
||||
|
||||
SetTouch( NULL );
|
||||
SetThink( NULL );
|
||||
|
||||
UTIL_Remove( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
trace_t tr;
|
||||
tr = BaseClass::GetTouchTrace();
|
||||
|
||||
// See if we struck the world
|
||||
if ( pOther->GetMoveType() == MOVETYPE_NONE && !( tr.surface.flags & SURF_SKY ) )
|
||||
{
|
||||
EmitSound( "Weapon_Crossbow.BoltHitWorld" );
|
||||
|
||||
// if what we hit is static architecture, can stay around for a while.
|
||||
Vector vecDir = GetAbsVelocity();
|
||||
float speed = VectorNormalize( vecDir );
|
||||
|
||||
// See if we should reflect off this surface
|
||||
float hitDot = DotProduct( tr.plane.normal, -vecDir );
|
||||
|
||||
if ( ( hitDot < 0.5f ) && ( speed > 100 ) )
|
||||
{
|
||||
Vector vReflection = 2.0f * tr.plane.normal * hitDot + vecDir;
|
||||
|
||||
QAngle reflectAngles;
|
||||
|
||||
VectorAngles( vReflection, reflectAngles );
|
||||
|
||||
SetLocalAngles( reflectAngles );
|
||||
|
||||
SetAbsVelocity( vReflection * speed * 0.75f );
|
||||
|
||||
// Start to sink faster
|
||||
SetGravity( 1.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
SetThink( &CCrossbowBolt::SUB_Remove );
|
||||
SetNextThink( gpGlobals->curtime + 2.0f );
|
||||
|
||||
//FIXME: We actually want to stick (with hierarchy) to what we've hit
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
|
||||
Vector vForward;
|
||||
|
||||
AngleVectors( GetAbsAngles(), &vForward );
|
||||
VectorNormalize ( vForward );
|
||||
|
||||
CEffectData data;
|
||||
|
||||
data.m_vOrigin = tr.endpos;
|
||||
data.m_vNormal = vForward;
|
||||
data.m_nEntIndex = 0;
|
||||
|
||||
DispatchEffect( "BoltImpact", data );
|
||||
|
||||
UTIL_ImpactTrace( &tr, DMG_BULLET );
|
||||
|
||||
AddEffects( EF_NODRAW );
|
||||
SetTouch( NULL );
|
||||
SetThink( &CCrossbowBolt::SUB_Remove );
|
||||
SetNextThink( gpGlobals->curtime + 2.0f );
|
||||
|
||||
if ( m_pGlowSprite != NULL )
|
||||
{
|
||||
m_pGlowSprite->TurnOn();
|
||||
m_pGlowSprite->FadeAndDie( 3.0f );
|
||||
}
|
||||
}
|
||||
|
||||
// Shoot some sparks
|
||||
if ( UTIL_PointContents( GetAbsOrigin() ) != CONTENTS_WATER)
|
||||
{
|
||||
g_pEffects->Sparks( GetAbsOrigin() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Put a mark unless we've hit the sky
|
||||
if ( ( tr.surface.flags & SURF_SKY ) == false )
|
||||
{
|
||||
UTIL_ImpactTrace( &tr, DMG_BULLET );
|
||||
}
|
||||
|
||||
UTIL_Remove( this );
|
||||
}
|
||||
}
|
||||
|
||||
if ( g_pGameRules->IsMultiplayer() )
|
||||
{
|
||||
// SetThink( &CCrossbowBolt::ExplodeThink );
|
||||
// SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCrossbowBolt::BubbleThink( void )
|
||||
{
|
||||
QAngle angNewAngles;
|
||||
|
||||
VectorAngles( GetAbsVelocity(), angNewAngles );
|
||||
SetAbsAngles( angNewAngles );
|
||||
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
|
||||
if ( GetWaterLevel() == 0 )
|
||||
return;
|
||||
|
||||
UTIL_BubbleTrail( GetAbsOrigin() - GetAbsVelocity() * 0.1f, GetAbsOrigin(), 5 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CWeaponCrossbow
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CWeaponCrossbow C_WeaponCrossbow
|
||||
#endif
|
||||
|
||||
class CWeaponCrossbow : public CBaseHL2MPCombatWeapon
|
||||
{
|
||||
DECLARE_CLASS( CWeaponCrossbow, CBaseHL2MPCombatWeapon );
|
||||
public:
|
||||
|
||||
CWeaponCrossbow( void );
|
||||
|
||||
virtual void Precache( void );
|
||||
virtual void PrimaryAttack( void );
|
||||
virtual void SecondaryAttack( void );
|
||||
virtual bool Deploy( void );
|
||||
virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
|
||||
virtual bool Reload( void );
|
||||
virtual void ItemPostFrame( void );
|
||||
virtual void ItemBusyFrame( void );
|
||||
virtual bool SendWeaponAnim( int iActivity );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
virtual void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
|
||||
#endif
|
||||
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
private:
|
||||
|
||||
void SetSkin( int skinNum );
|
||||
void CheckZoomToggle( void );
|
||||
void FireBolt( void );
|
||||
void ToggleZoom( void );
|
||||
|
||||
// Various states for the crossbow's charger
|
||||
enum ChargerState_t
|
||||
{
|
||||
CHARGER_STATE_START_LOAD,
|
||||
CHARGER_STATE_START_CHARGE,
|
||||
CHARGER_STATE_READY,
|
||||
CHARGER_STATE_DISCHARGE,
|
||||
CHARGER_STATE_OFF,
|
||||
};
|
||||
|
||||
void CreateChargerEffects( void );
|
||||
void SetChargerState( ChargerState_t state );
|
||||
void DoLoadEffect( void );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_ACTTABLE();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
// Charger effects
|
||||
ChargerState_t m_nChargeState;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
CHandle<CSprite> m_hChargerSprite;
|
||||
#endif
|
||||
|
||||
CNetworkVar( bool, m_bInZoom );
|
||||
CNetworkVar( bool, m_bMustReload );
|
||||
|
||||
CWeaponCrossbow( const CWeaponCrossbow & );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCrossbow, DT_WeaponCrossbow )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponCrossbow, DT_WeaponCrossbow )
|
||||
#ifdef CLIENT_DLL
|
||||
RecvPropBool( RECVINFO( m_bInZoom ) ),
|
||||
RecvPropBool( RECVINFO( m_bMustReload ) ),
|
||||
#else
|
||||
SendPropBool( SENDINFO( m_bInZoom ) ),
|
||||
SendPropBool( SENDINFO( m_bMustReload ) ),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
BEGIN_PREDICTION_DATA( CWeaponCrossbow )
|
||||
DEFINE_PRED_FIELD( m_bInZoom, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_bMustReload, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_crossbow, CWeaponCrossbow );
|
||||
|
||||
PRECACHE_WEAPON_REGISTER( weapon_crossbow );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
acttable_t CWeaponCrossbow::m_acttable[] =
|
||||
{
|
||||
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_CROSSBOW, false },
|
||||
{ ACT_HL2MP_RUN, ACT_HL2MP_RUN_CROSSBOW, false },
|
||||
{ ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_CROSSBOW, false },
|
||||
{ ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_CROSSBOW, false },
|
||||
{ ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW, false },
|
||||
{ ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_CROSSBOW, false },
|
||||
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_CROSSBOW, false },
|
||||
};
|
||||
|
||||
IMPLEMENT_ACTTABLE(CWeaponCrossbow);
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CWeaponCrossbow::CWeaponCrossbow( void )
|
||||
{
|
||||
m_bReloadsSingly = true;
|
||||
m_bFiresUnderwater = true;
|
||||
m_bInZoom = false;
|
||||
m_bMustReload = false;
|
||||
}
|
||||
|
||||
#define CROSSBOW_GLOW_SPRITE "sprites/light_glow02_noz.vmt"
|
||||
#define CROSSBOW_GLOW_SPRITE2 "sprites/blueflare1.vmt"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrossbow::Precache( void )
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
UTIL_PrecacheOther( "crossbow_bolt" );
|
||||
#endif
|
||||
|
||||
PrecacheScriptSound( "Weapon_Crossbow.BoltHitBody" );
|
||||
PrecacheScriptSound( "Weapon_Crossbow.BoltHitWorld" );
|
||||
PrecacheScriptSound( "Weapon_Crossbow.BoltSkewer" );
|
||||
|
||||
PrecacheModel( CROSSBOW_GLOW_SPRITE );
|
||||
PrecacheModel( CROSSBOW_GLOW_SPRITE2 );
|
||||
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrossbow::PrimaryAttack( void )
|
||||
{
|
||||
if ( m_bInZoom && g_pGameRules->IsMultiplayer() )
|
||||
{
|
||||
// FireSniperBolt();
|
||||
FireBolt();
|
||||
}
|
||||
else
|
||||
{
|
||||
FireBolt();
|
||||
}
|
||||
|
||||
// Signal a reload
|
||||
m_bMustReload = true;
|
||||
|
||||
SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration( ACT_VM_PRIMARYATTACK ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrossbow::SecondaryAttack( void )
|
||||
{
|
||||
//NOTENOTE: The zooming is handled by the post/busy frames
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponCrossbow::Reload( void )
|
||||
{
|
||||
if ( BaseClass::Reload() )
|
||||
{
|
||||
m_bMustReload = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrossbow::CheckZoomToggle( void )
|
||||
{
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pPlayer->m_afButtonPressed & IN_ATTACK2 )
|
||||
{
|
||||
ToggleZoom();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrossbow::ItemBusyFrame( void )
|
||||
{
|
||||
// Allow zoom toggling even when we're reloading
|
||||
CheckZoomToggle();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrossbow::ItemPostFrame( void )
|
||||
{
|
||||
// Allow zoom toggling
|
||||
CheckZoomToggle();
|
||||
|
||||
if ( m_bMustReload && HasWeaponIdleTimeElapsed() )
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
|
||||
BaseClass::ItemPostFrame();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrossbow::FireBolt( void )
|
||||
{
|
||||
if ( m_iClip1 <= 0 )
|
||||
{
|
||||
if ( !m_bFireOnEmpty )
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
WeaponSound( EMPTY );
|
||||
m_flNextPrimaryAttack = 0.15;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pOwner == NULL )
|
||||
return;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
Vector vecAiming = pOwner->GetAutoaimVector( 0 );
|
||||
Vector vecSrc = pOwner->Weapon_ShootPosition();
|
||||
|
||||
QAngle angAiming;
|
||||
VectorAngles( vecAiming, angAiming );
|
||||
|
||||
CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate( vecSrc, angAiming, GetHL2MPWpnData().m_iPlayerDamage, pOwner );
|
||||
|
||||
if ( pOwner->GetWaterLevel() == 3 )
|
||||
{
|
||||
pBolt->SetAbsVelocity( vecAiming * BOLT_WATER_VELOCITY );
|
||||
}
|
||||
else
|
||||
{
|
||||
pBolt->SetAbsVelocity( vecAiming * BOLT_AIR_VELOCITY );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
m_iClip1--;
|
||||
|
||||
pOwner->ViewPunch( QAngle( -2, 0, 0 ) );
|
||||
|
||||
WeaponSound( SINGLE );
|
||||
WeaponSound( SPECIAL2 );
|
||||
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
||||
|
||||
if ( !m_iClip1 && pOwner->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
|
||||
{
|
||||
// HEV suit - indicate out of ammo condition
|
||||
pOwner->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
|
||||
}
|
||||
|
||||
m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + 0.75;
|
||||
|
||||
DoLoadEffect();
|
||||
SetChargerState( CHARGER_STATE_DISCHARGE );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponCrossbow::Deploy( void )
|
||||
{
|
||||
if ( m_iClip1 <= 0 )
|
||||
{
|
||||
return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_CROSSBOW_DRAW_UNLOADED, (char*)GetAnimPrefix() );
|
||||
}
|
||||
|
||||
SetSkin( BOLT_SKIN_GLOW );
|
||||
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pSwitchingTo -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponCrossbow::Holster( CBaseCombatWeapon *pSwitchingTo )
|
||||
{
|
||||
if ( m_bInZoom )
|
||||
{
|
||||
ToggleZoom();
|
||||
}
|
||||
|
||||
SetChargerState( CHARGER_STATE_OFF );
|
||||
|
||||
return BaseClass::Holster( pSwitchingTo );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrossbow::ToggleZoom( void )
|
||||
{
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pPlayer == NULL )
|
||||
return;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
if ( m_bInZoom )
|
||||
{
|
||||
if ( pPlayer->SetFOV( this, 0, 0.2f ) )
|
||||
{
|
||||
m_bInZoom = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( pPlayer->SetFOV( this, 20, 0.1f ) )
|
||||
{
|
||||
m_bInZoom = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define BOLT_TIP_ATTACHMENT 2
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrossbow::CreateChargerEffects( void )
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( m_hChargerSprite != NULL )
|
||||
return;
|
||||
|
||||
m_hChargerSprite = CSprite::SpriteCreate( CROSSBOW_GLOW_SPRITE, GetAbsOrigin(), false );
|
||||
|
||||
if ( m_hChargerSprite )
|
||||
{
|
||||
m_hChargerSprite->SetAttachment( pOwner->GetViewModel(), BOLT_TIP_ATTACHMENT );
|
||||
m_hChargerSprite->SetTransparency( kRenderTransAdd, 255, 128, 0, 255, kRenderFxNoDissipation );
|
||||
m_hChargerSprite->SetBrightness( 0 );
|
||||
m_hChargerSprite->SetScale( 0.1f );
|
||||
m_hChargerSprite->TurnOff();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : skinNum -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrossbow::SetSkin( int skinNum )
|
||||
{
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pOwner == NULL )
|
||||
return;
|
||||
|
||||
CBaseViewModel *pViewModel = pOwner->GetViewModel();
|
||||
|
||||
if ( pViewModel == NULL )
|
||||
return;
|
||||
|
||||
pViewModel->m_nSkin = skinNum;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrossbow::DoLoadEffect( void )
|
||||
{
|
||||
SetSkin( BOLT_SKIN_GLOW );
|
||||
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pOwner == NULL )
|
||||
return;
|
||||
|
||||
CBaseViewModel *pViewModel = pOwner->GetViewModel();
|
||||
|
||||
if ( pViewModel == NULL )
|
||||
return;
|
||||
|
||||
CEffectData data;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
data.m_hEntity = pViewModel->GetRefEHandle();
|
||||
#else
|
||||
data.m_nEntIndex = pViewModel->entindex();
|
||||
#endif
|
||||
data.m_nAttachmentIndex = 1;
|
||||
|
||||
DispatchEffect( "CrossbowLoad", data );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
CSprite *pBlast = CSprite::SpriteCreate( CROSSBOW_GLOW_SPRITE2, GetAbsOrigin(), false );
|
||||
|
||||
if ( pBlast )
|
||||
{
|
||||
pBlast->SetAttachment( pOwner->GetViewModel(), 1 );
|
||||
pBlast->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNone );
|
||||
pBlast->SetBrightness( 128 );
|
||||
pBlast->SetScale( 0.2f );
|
||||
pBlast->FadeOutFromSpawn();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : state -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrossbow::SetChargerState( ChargerState_t state )
|
||||
{
|
||||
// Make sure we're setup
|
||||
CreateChargerEffects();
|
||||
|
||||
// Don't do this twice
|
||||
if ( state == m_nChargeState )
|
||||
return;
|
||||
|
||||
m_nChargeState = state;
|
||||
|
||||
switch( m_nChargeState )
|
||||
{
|
||||
case CHARGER_STATE_START_LOAD:
|
||||
|
||||
WeaponSound( SPECIAL1 );
|
||||
|
||||
// Shoot some sparks and draw a beam between the two outer points
|
||||
DoLoadEffect();
|
||||
|
||||
break;
|
||||
#ifndef CLIENT_DLL
|
||||
case CHARGER_STATE_START_CHARGE:
|
||||
{
|
||||
if ( m_hChargerSprite == NULL )
|
||||
break;
|
||||
|
||||
m_hChargerSprite->SetBrightness( 32, 0.5f );
|
||||
m_hChargerSprite->SetScale( 0.025f, 0.5f );
|
||||
m_hChargerSprite->TurnOn();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CHARGER_STATE_READY:
|
||||
{
|
||||
// Get fully charged
|
||||
if ( m_hChargerSprite == NULL )
|
||||
break;
|
||||
|
||||
m_hChargerSprite->SetBrightness( 80, 1.0f );
|
||||
m_hChargerSprite->SetScale( 0.1f, 0.5f );
|
||||
m_hChargerSprite->TurnOn();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CHARGER_STATE_DISCHARGE:
|
||||
{
|
||||
SetSkin( BOLT_SKIN_NORMAL );
|
||||
|
||||
if ( m_hChargerSprite == NULL )
|
||||
break;
|
||||
|
||||
m_hChargerSprite->SetBrightness( 0 );
|
||||
m_hChargerSprite->TurnOff();
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
case CHARGER_STATE_OFF:
|
||||
{
|
||||
SetSkin( BOLT_SKIN_NORMAL );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
if ( m_hChargerSprite == NULL )
|
||||
break;
|
||||
|
||||
m_hChargerSprite->SetBrightness( 0 );
|
||||
m_hChargerSprite->TurnOff();
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pEvent -
|
||||
// *pOperator -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrossbow::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
|
||||
{
|
||||
switch( pEvent->event )
|
||||
{
|
||||
case EVENT_WEAPON_THROW:
|
||||
SetChargerState( CHARGER_STATE_START_LOAD );
|
||||
break;
|
||||
|
||||
case EVENT_WEAPON_THROW2:
|
||||
SetChargerState( CHARGER_STATE_START_CHARGE );
|
||||
break;
|
||||
|
||||
case EVENT_WEAPON_THROW3:
|
||||
SetChargerState( CHARGER_STATE_READY );
|
||||
break;
|
||||
|
||||
default:
|
||||
BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set the desired activity for the weapon and its viewmodel counterpart
|
||||
// Input : iActivity - activity to play
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponCrossbow::SendWeaponAnim( int iActivity )
|
||||
{
|
||||
int newActivity = iActivity;
|
||||
|
||||
// The last shot needs a non-loaded activity
|
||||
if ( ( newActivity == ACT_VM_IDLE ) && ( m_iClip1 <= 0 ) )
|
||||
{
|
||||
newActivity = ACT_VM_FIDGET;
|
||||
}
|
||||
|
||||
//For now, just set the ideal activity and be done with it
|
||||
return BaseClass::SendWeaponAnim( newActivity );
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Crowbar - an old favorite
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "hl2mp/weapon_crowbar.h"
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
#include "gamerules.h"
|
||||
#include "ammodef.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
#include "in_buttons.h"
|
||||
#include "vstdlib/random.h"
|
||||
#include "npcevent.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#include "c_hl2mp_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "ai_basenpc.h"
|
||||
#endif
|
||||
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define CROWBAR_RANGE 75.0f
|
||||
#define CROWBAR_REFIRE 0.4f
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CWeaponCrowbar
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCrowbar, DT_WeaponCrowbar )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponCrowbar, DT_WeaponCrowbar )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponCrowbar )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_crowbar, CWeaponCrowbar );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_crowbar );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
acttable_t CWeaponCrowbar::m_acttable[] =
|
||||
{
|
||||
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true },
|
||||
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_MELEE, false },
|
||||
{ ACT_HL2MP_RUN, ACT_HL2MP_RUN_MELEE, false },
|
||||
{ ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_MELEE, false },
|
||||
{ ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_MELEE, false },
|
||||
{ ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE, false },
|
||||
{ ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_MELEE, false },
|
||||
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_MELEE, false },
|
||||
};
|
||||
|
||||
IMPLEMENT_ACTTABLE(CWeaponCrowbar);
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CWeaponCrowbar::CWeaponCrowbar( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get the damage amount for the animation we're doing
|
||||
// Input : hitActivity - currently played activity
|
||||
// Output : Damage amount
|
||||
//-----------------------------------------------------------------------------
|
||||
float CWeaponCrowbar::GetDamageForActivity( Activity hitActivity )
|
||||
{
|
||||
return 25.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Add in a view kick for this weapon
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrowbar::AddViewKick( void )
|
||||
{
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pPlayer == NULL )
|
||||
return;
|
||||
|
||||
QAngle punchAng;
|
||||
|
||||
punchAng.x = SharedRandomFloat( "crowbarpax", 1.0f, 2.0f );
|
||||
punchAng.y = SharedRandomFloat( "crowbarpay", -2.0f, -1.0f );
|
||||
punchAng.z = 0.0f;
|
||||
|
||||
pPlayer->ViewPunch( punchAng );
|
||||
}
|
||||
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
//-----------------------------------------------------------------------------
|
||||
// Animation event handlers
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrowbar::HandleAnimEventMeleeHit( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
|
||||
{
|
||||
// Trace up or down based on where the enemy is...
|
||||
// But only if we're basically facing that direction
|
||||
Vector vecDirection;
|
||||
AngleVectors( GetAbsAngles(), &vecDirection );
|
||||
|
||||
Vector vecEnd;
|
||||
VectorMA( pOperator->Weapon_ShootPosition(), 50, vecDirection, vecEnd );
|
||||
CBaseEntity *pHurt = pOperator->CheckTraceHullAttack( pOperator->Weapon_ShootPosition(), vecEnd,
|
||||
Vector(-16,-16,-16), Vector(36,36,36), GetDamageForActivity( GetActivity() ), DMG_CLUB, 0.75 );
|
||||
|
||||
// did I hit someone?
|
||||
if ( pHurt )
|
||||
{
|
||||
// play sound
|
||||
WeaponSound( MELEE_HIT );
|
||||
|
||||
// Fake a trace impact, so the effects work out like a player's crowbaw
|
||||
trace_t traceHit;
|
||||
UTIL_TraceLine( pOperator->Weapon_ShootPosition(), pHurt->GetAbsOrigin(), MASK_SHOT_HULL, pOperator, COLLISION_GROUP_NONE, &traceHit );
|
||||
ImpactEffect( traceHit );
|
||||
}
|
||||
else
|
||||
{
|
||||
WeaponSound( MELEE_MISS );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Animation event
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrowbar::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
|
||||
{
|
||||
switch( pEvent->event )
|
||||
{
|
||||
case EVENT_WEAPON_MELEE_HIT:
|
||||
HandleAnimEventMeleeHit( pEvent, pOperator );
|
||||
break;
|
||||
|
||||
default:
|
||||
BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Attempt to lead the target (needed because citizens can't hit manhacks with the crowbar!)
|
||||
//-----------------------------------------------------------------------------
|
||||
ConVar sk_crowbar_lead_time( "sk_crowbar_lead_time", "0.9" );
|
||||
|
||||
int CWeaponCrowbar::WeaponMeleeAttack1Condition( float flDot, float flDist )
|
||||
{
|
||||
// Attempt to lead the target (needed because citizens can't hit manhacks with the crowbar!)
|
||||
CAI_BaseNPC *pNPC = GetOwner()->MyNPCPointer();
|
||||
CBaseEntity *pEnemy = pNPC->GetEnemy();
|
||||
if (!pEnemy)
|
||||
return COND_NONE;
|
||||
|
||||
Vector vecVelocity;
|
||||
vecVelocity = pEnemy->GetSmoothedVelocity( );
|
||||
|
||||
// Project where the enemy will be in a little while
|
||||
float dt = sk_crowbar_lead_time.GetFloat();
|
||||
dt += SharedRandomFloat( "crowbarmelee1", -0.3f, 0.2f );
|
||||
if ( dt < 0.0f )
|
||||
dt = 0.0f;
|
||||
|
||||
Vector vecExtrapolatedPos;
|
||||
VectorMA( pEnemy->WorldSpaceCenter(), dt, vecVelocity, vecExtrapolatedPos );
|
||||
|
||||
Vector vecDelta;
|
||||
VectorSubtract( vecExtrapolatedPos, pNPC->WorldSpaceCenter(), vecDelta );
|
||||
|
||||
if ( fabs( vecDelta.z ) > 70 )
|
||||
{
|
||||
return COND_TOO_FAR_TO_ATTACK;
|
||||
}
|
||||
|
||||
Vector vecForward = pNPC->BodyDirection2D( );
|
||||
vecDelta.z = 0.0f;
|
||||
float flExtrapolatedDist = Vector2DNormalize( vecDelta.AsVector2D() );
|
||||
if ((flDist > 64) && (flExtrapolatedDist > 64))
|
||||
{
|
||||
return COND_TOO_FAR_TO_ATTACK;
|
||||
}
|
||||
|
||||
float flExtrapolatedDot = DotProduct2D( vecDelta.AsVector2D(), vecForward.AsVector2D() );
|
||||
if ((flDot < 0.7) && (flExtrapolatedDot < 0.7))
|
||||
{
|
||||
return COND_NOT_FACING_ATTACK;
|
||||
}
|
||||
|
||||
return COND_CAN_MELEE_ATTACK1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCrowbar::Drop( const Vector &vecVelocity )
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
UTIL_Remove( this );
|
||||
#endif
|
||||
}
|
||||
|
||||
float CWeaponCrowbar::GetRange( void )
|
||||
{
|
||||
return CROWBAR_RANGE;
|
||||
}
|
||||
|
||||
float CWeaponCrowbar::GetFireRate( void )
|
||||
{
|
||||
return CROWBAR_REFIRE;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef HL2MP_WEAPON_CROWBAR_H
|
||||
#define HL2MP_WEAPON_CROWBAR_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
#include "weapon_hl2mpbasebasebludgeon.h"
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CWeaponCrowbar C_WeaponCrowbar
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CWeaponCrowbar
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class CWeaponCrowbar : public CBaseHL2MPBludgeonWeapon
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponCrowbar, CBaseHL2MPBludgeonWeapon );
|
||||
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_ACTTABLE();
|
||||
#endif
|
||||
|
||||
CWeaponCrowbar();
|
||||
|
||||
float GetRange( void );
|
||||
float GetFireRate( void );
|
||||
|
||||
void AddViewKick( void );
|
||||
float GetDamageForActivity( Activity hitActivity );
|
||||
void SecondaryAttack( void ) { return; }
|
||||
|
||||
void Drop( const Vector &vecVelocity );
|
||||
|
||||
|
||||
// Animation event
|
||||
#ifndef CLIENT_DLL
|
||||
virtual void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
|
||||
void HandleAnimEventMeleeHit( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
|
||||
int WeaponMeleeAttack1Condition( float flDot, float flDist );
|
||||
#endif
|
||||
|
||||
CWeaponCrowbar( const CWeaponCrowbar & );
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // HL2MP_WEAPON_CROWBAR_H
|
||||
|
||||
@@ -0,0 +1,552 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "npcevent.h"
|
||||
#include "in_buttons.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "c_te_effect_dispatch.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "te_effect_dispatch.h"
|
||||
#include "grenade_frag.h"
|
||||
#endif
|
||||
|
||||
#include "weapon_ar2.h"
|
||||
#include "effect_dispatch_data.h"
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define GRENADE_TIMER 2.5f //Seconds
|
||||
|
||||
#define GRENADE_PAUSED_NO 0
|
||||
#define GRENADE_PAUSED_PRIMARY 1
|
||||
#define GRENADE_PAUSED_SECONDARY 2
|
||||
|
||||
#define GRENADE_RADIUS 4.0f // inches
|
||||
|
||||
#define GRENADE_DAMAGE_RADIUS 250.0f
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CWeaponFrag C_WeaponFrag
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Fragmentation grenades
|
||||
//-----------------------------------------------------------------------------
|
||||
class CWeaponFrag: public CBaseHL2MPCombatWeapon
|
||||
{
|
||||
DECLARE_CLASS( CWeaponFrag, CBaseHL2MPCombatWeapon );
|
||||
public:
|
||||
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponFrag();
|
||||
|
||||
void Precache( void );
|
||||
void PrimaryAttack( void );
|
||||
void SecondaryAttack( void );
|
||||
void DecrementAmmo( CBaseCombatCharacter *pOwner );
|
||||
void ItemPostFrame( void );
|
||||
|
||||
bool Deploy( void );
|
||||
bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
|
||||
|
||||
bool Reload( void );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
|
||||
#endif
|
||||
|
||||
void ThrowGrenade( CBasePlayer *pPlayer );
|
||||
bool IsPrimed( bool ) { return ( m_AttackPaused != 0 ); }
|
||||
|
||||
private:
|
||||
|
||||
void RollGrenade( CBasePlayer *pPlayer );
|
||||
void LobGrenade( CBasePlayer *pPlayer );
|
||||
// check a throw from vecSrc. If not valid, move the position back along the line to vecEye
|
||||
void CheckThrowPosition( CBasePlayer *pPlayer, const Vector &vecEye, Vector &vecSrc );
|
||||
|
||||
CNetworkVar( bool, m_bRedraw ); //Draw the weapon again after throwing a grenade
|
||||
|
||||
CNetworkVar( int, m_AttackPaused );
|
||||
CNetworkVar( bool, m_fDrawbackFinished );
|
||||
|
||||
CWeaponFrag( const CWeaponFrag & );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_ACTTABLE();
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
acttable_t CWeaponFrag::m_acttable[] =
|
||||
{
|
||||
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_GRENADE, false },
|
||||
{ ACT_HL2MP_RUN, ACT_HL2MP_RUN_GRENADE, false },
|
||||
{ ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_GRENADE, false },
|
||||
{ ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_GRENADE, false },
|
||||
{ ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE, false },
|
||||
{ ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_GRENADE, false },
|
||||
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_GRENADE, false },
|
||||
};
|
||||
|
||||
IMPLEMENT_ACTTABLE(CWeaponFrag);
|
||||
|
||||
#endif
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponFrag, DT_WeaponFrag )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponFrag, DT_WeaponFrag )
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
RecvPropBool( RECVINFO( m_bRedraw ) ),
|
||||
RecvPropBool( RECVINFO( m_fDrawbackFinished ) ),
|
||||
RecvPropInt( RECVINFO( m_AttackPaused ) ),
|
||||
#else
|
||||
SendPropBool( SENDINFO( m_bRedraw ) ),
|
||||
SendPropBool( SENDINFO( m_fDrawbackFinished ) ),
|
||||
SendPropInt( SENDINFO( m_AttackPaused ) ),
|
||||
#endif
|
||||
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
BEGIN_PREDICTION_DATA( CWeaponFrag )
|
||||
DEFINE_PRED_FIELD( m_bRedraw, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_fDrawbackFinished, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_AttackPaused, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_frag, CWeaponFrag );
|
||||
PRECACHE_WEAPON_REGISTER(weapon_frag);
|
||||
|
||||
CWeaponFrag::CWeaponFrag( void ) :
|
||||
CBaseHL2MPCombatWeapon()
|
||||
{
|
||||
m_bRedraw = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponFrag::Precache( void )
|
||||
{
|
||||
BaseClass::Precache();
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
UTIL_PrecacheOther( "npc_grenade_frag" );
|
||||
#endif
|
||||
|
||||
PrecacheScriptSound( "WeaponFrag.Throw" );
|
||||
PrecacheScriptSound( "WeaponFrag.Roll" );
|
||||
}
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pEvent -
|
||||
// *pOperator -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponFrag::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
|
||||
{
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
bool fThrewGrenade = false;
|
||||
|
||||
switch( pEvent->event )
|
||||
{
|
||||
case EVENT_WEAPON_SEQUENCE_FINISHED:
|
||||
m_fDrawbackFinished = true;
|
||||
break;
|
||||
|
||||
case EVENT_WEAPON_THROW:
|
||||
ThrowGrenade( pOwner );
|
||||
DecrementAmmo( pOwner );
|
||||
fThrewGrenade = true;
|
||||
break;
|
||||
|
||||
case EVENT_WEAPON_THROW2:
|
||||
RollGrenade( pOwner );
|
||||
DecrementAmmo( pOwner );
|
||||
fThrewGrenade = true;
|
||||
break;
|
||||
|
||||
case EVENT_WEAPON_THROW3:
|
||||
LobGrenade( pOwner );
|
||||
DecrementAmmo( pOwner );
|
||||
fThrewGrenade = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
|
||||
break;
|
||||
}
|
||||
|
||||
#define RETHROW_DELAY 0.5
|
||||
if( fThrewGrenade )
|
||||
{
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + RETHROW_DELAY;
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + RETHROW_DELAY;
|
||||
m_flTimeWeaponIdle = FLT_MAX; //NOTE: This is set once the animation has finished up!
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponFrag::Deploy( void )
|
||||
{
|
||||
m_bRedraw = false;
|
||||
m_fDrawbackFinished = false;
|
||||
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponFrag::Holster( CBaseCombatWeapon *pSwitchingTo )
|
||||
{
|
||||
m_bRedraw = false;
|
||||
m_fDrawbackFinished = false;
|
||||
|
||||
return BaseClass::Holster( pSwitchingTo );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponFrag::Reload( void )
|
||||
{
|
||||
if ( !HasPrimaryAmmo() )
|
||||
return false;
|
||||
|
||||
if ( ( m_bRedraw ) && ( m_flNextPrimaryAttack <= gpGlobals->curtime ) && ( m_flNextSecondaryAttack <= gpGlobals->curtime ) )
|
||||
{
|
||||
//Redraw the weapon
|
||||
SendWeaponAnim( ACT_VM_DRAW );
|
||||
|
||||
//Update our times
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
|
||||
|
||||
//Mark this as done
|
||||
m_bRedraw = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponFrag::SecondaryAttack( void )
|
||||
{
|
||||
if ( m_bRedraw )
|
||||
return;
|
||||
|
||||
if ( !HasPrimaryAmmo() )
|
||||
return;
|
||||
|
||||
CBaseCombatCharacter *pOwner = GetOwner();
|
||||
|
||||
if ( pOwner == NULL )
|
||||
return;
|
||||
|
||||
CBasePlayer *pPlayer = ToBasePlayer( pOwner );
|
||||
|
||||
if ( pPlayer == NULL )
|
||||
return;
|
||||
|
||||
// Note that this is a secondary attack and prepare the grenade attack to pause.
|
||||
m_AttackPaused = GRENADE_PAUSED_SECONDARY;
|
||||
SendWeaponAnim( ACT_VM_PULLBACK_LOW );
|
||||
|
||||
// Don't let weapon idle interfere in the middle of a throw!
|
||||
m_flTimeWeaponIdle = FLT_MAX;
|
||||
m_flNextSecondaryAttack = FLT_MAX;
|
||||
|
||||
// If I'm now out of ammo, switch away
|
||||
if ( !HasPrimaryAmmo() )
|
||||
{
|
||||
pPlayer->SwitchToNextBestWeapon( this );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponFrag::PrimaryAttack( void )
|
||||
{
|
||||
if ( m_bRedraw )
|
||||
return;
|
||||
|
||||
CBaseCombatCharacter *pOwner = GetOwner();
|
||||
|
||||
if ( pOwner == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );;
|
||||
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
// Note that this is a primary attack and prepare the grenade attack to pause.
|
||||
m_AttackPaused = GRENADE_PAUSED_PRIMARY;
|
||||
SendWeaponAnim( ACT_VM_PULLBACK_HIGH );
|
||||
|
||||
// Put both of these off indefinitely. We do not know how long
|
||||
// the player will hold the grenade.
|
||||
m_flTimeWeaponIdle = FLT_MAX;
|
||||
m_flNextPrimaryAttack = FLT_MAX;
|
||||
|
||||
// If I'm now out of ammo, switch away
|
||||
if ( !HasPrimaryAmmo() )
|
||||
{
|
||||
pPlayer->SwitchToNextBestWeapon( this );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pOwner -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponFrag::DecrementAmmo( CBaseCombatCharacter *pOwner )
|
||||
{
|
||||
pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponFrag::ItemPostFrame( void )
|
||||
{
|
||||
if( m_fDrawbackFinished )
|
||||
{
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
|
||||
if (pOwner)
|
||||
{
|
||||
switch( m_AttackPaused )
|
||||
{
|
||||
case GRENADE_PAUSED_PRIMARY:
|
||||
if( !(pOwner->m_nButtons & IN_ATTACK) )
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_THROW );
|
||||
m_fDrawbackFinished = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRENADE_PAUSED_SECONDARY:
|
||||
if( !(pOwner->m_nButtons & IN_ATTACK2) )
|
||||
{
|
||||
//See if we're ducking
|
||||
if ( pOwner->m_nButtons & IN_DUCK )
|
||||
{
|
||||
//Send the weapon animation
|
||||
SendWeaponAnim( ACT_VM_SECONDARYATTACK );
|
||||
}
|
||||
else
|
||||
{
|
||||
//Send the weapon animation
|
||||
SendWeaponAnim( ACT_VM_HAULBACK );
|
||||
}
|
||||
|
||||
m_fDrawbackFinished = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BaseClass::ItemPostFrame();
|
||||
|
||||
if ( m_bRedraw )
|
||||
{
|
||||
if ( IsViewModelSequenceFinished() )
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check a throw from vecSrc. If not valid, move the position back along the line to vecEye
|
||||
void CWeaponFrag::CheckThrowPosition( CBasePlayer *pPlayer, const Vector &vecEye, Vector &vecSrc )
|
||||
{
|
||||
trace_t tr;
|
||||
|
||||
UTIL_TraceHull( vecEye, vecSrc, -Vector(GRENADE_RADIUS+2,GRENADE_RADIUS+2,GRENADE_RADIUS+2), Vector(GRENADE_RADIUS+2,GRENADE_RADIUS+2,GRENADE_RADIUS+2),
|
||||
pPlayer->PhysicsSolidMaskForEntity(), pPlayer, pPlayer->GetCollisionGroup(), &tr );
|
||||
|
||||
if ( tr.DidHit() )
|
||||
{
|
||||
vecSrc = tr.endpos;
|
||||
}
|
||||
}
|
||||
|
||||
void DropPrimedFragGrenade( CHL2MP_Player *pPlayer, CBaseCombatWeapon *pGrenade )
|
||||
{
|
||||
CWeaponFrag *pWeaponFrag = dynamic_cast<CWeaponFrag*>( pGrenade );
|
||||
|
||||
if ( pWeaponFrag )
|
||||
{
|
||||
pWeaponFrag->ThrowGrenade( pPlayer );
|
||||
pWeaponFrag->DecrementAmmo( pPlayer );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pPlayer -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponFrag::ThrowGrenade( CBasePlayer *pPlayer )
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
Vector vecEye = pPlayer->EyePosition();
|
||||
Vector vForward, vRight;
|
||||
|
||||
pPlayer->EyeVectors( &vForward, &vRight, NULL );
|
||||
Vector vecSrc = vecEye + vForward * 18.0f + vRight * 8.0f;
|
||||
CheckThrowPosition( pPlayer, vecEye, vecSrc );
|
||||
// vForward[0] += 0.1f;
|
||||
vForward[2] += 0.1f;
|
||||
|
||||
Vector vecThrow;
|
||||
pPlayer->GetVelocity( &vecThrow, NULL );
|
||||
vecThrow += vForward * 1200;
|
||||
CBaseGrenade *pGrenade = Fraggrenade_Create( vecSrc, vec3_angle, vecThrow, AngularImpulse(600,random->RandomInt(-1200,1200),0), pPlayer, GRENADE_TIMER, false );
|
||||
|
||||
if ( pGrenade )
|
||||
{
|
||||
if ( pPlayer && pPlayer->m_lifeState != LIFE_ALIVE )
|
||||
{
|
||||
pPlayer->GetVelocity( &vecThrow, NULL );
|
||||
|
||||
IPhysicsObject *pPhysicsObject = pGrenade->VPhysicsGetObject();
|
||||
if ( pPhysicsObject )
|
||||
{
|
||||
pPhysicsObject->SetVelocity( &vecThrow, NULL );
|
||||
}
|
||||
}
|
||||
|
||||
pGrenade->SetDamage( GetHL2MPWpnData().m_iPlayerDamage );
|
||||
pGrenade->SetDamageRadius( GRENADE_DAMAGE_RADIUS );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_bRedraw = true;
|
||||
|
||||
WeaponSound( SINGLE );
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pPlayer -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponFrag::LobGrenade( CBasePlayer *pPlayer )
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
Vector vecEye = pPlayer->EyePosition();
|
||||
Vector vForward, vRight;
|
||||
|
||||
pPlayer->EyeVectors( &vForward, &vRight, NULL );
|
||||
Vector vecSrc = vecEye + vForward * 18.0f + vRight * 8.0f + Vector( 0, 0, -8 );
|
||||
CheckThrowPosition( pPlayer, vecEye, vecSrc );
|
||||
|
||||
Vector vecThrow;
|
||||
pPlayer->GetVelocity( &vecThrow, NULL );
|
||||
vecThrow += vForward * 350 + Vector( 0, 0, 50 );
|
||||
CBaseGrenade *pGrenade = Fraggrenade_Create( vecSrc, vec3_angle, vecThrow, AngularImpulse(200,random->RandomInt(-600,600),0), pPlayer, GRENADE_TIMER, false );
|
||||
|
||||
if ( pGrenade )
|
||||
{
|
||||
pGrenade->SetDamage( GetHL2MPWpnData().m_iPlayerDamage );
|
||||
pGrenade->SetDamageRadius( GRENADE_DAMAGE_RADIUS );
|
||||
}
|
||||
#endif
|
||||
|
||||
WeaponSound( WPN_DOUBLE );
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
m_bRedraw = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pPlayer -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponFrag::RollGrenade( CBasePlayer *pPlayer )
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
// BUGBUG: Hardcoded grenade width of 4 - better not change the model :)
|
||||
Vector vecSrc;
|
||||
pPlayer->CollisionProp()->NormalizedToWorldSpace( Vector( 0.5f, 0.5f, 0.0f ), &vecSrc );
|
||||
vecSrc.z += GRENADE_RADIUS;
|
||||
|
||||
Vector vecFacing = pPlayer->BodyDirection2D( );
|
||||
// no up/down direction
|
||||
vecFacing.z = 0;
|
||||
VectorNormalize( vecFacing );
|
||||
trace_t tr;
|
||||
UTIL_TraceLine( vecSrc, vecSrc - Vector(0,0,16), MASK_PLAYERSOLID, pPlayer, COLLISION_GROUP_NONE, &tr );
|
||||
if ( tr.fraction != 1.0 )
|
||||
{
|
||||
// compute forward vec parallel to floor plane and roll grenade along that
|
||||
Vector tangent;
|
||||
CrossProduct( vecFacing, tr.plane.normal, tangent );
|
||||
CrossProduct( tr.plane.normal, tangent, vecFacing );
|
||||
}
|
||||
vecSrc += (vecFacing * 18.0);
|
||||
CheckThrowPosition( pPlayer, pPlayer->WorldSpaceCenter(), vecSrc );
|
||||
|
||||
Vector vecThrow;
|
||||
pPlayer->GetVelocity( &vecThrow, NULL );
|
||||
vecThrow += vecFacing * 700;
|
||||
// put it on its side
|
||||
QAngle orientation(0,pPlayer->GetLocalAngles().y,-90);
|
||||
// roll it
|
||||
AngularImpulse rotSpeed(0,0,720);
|
||||
CBaseGrenade *pGrenade = Fraggrenade_Create( vecSrc, orientation, vecThrow, rotSpeed, pPlayer, GRENADE_TIMER, false );
|
||||
|
||||
if ( pGrenade )
|
||||
{
|
||||
pGrenade->SetDamage( GetHL2MPWpnData().m_iPlayerDamage );
|
||||
pGrenade->SetDamageRadius( GRENADE_DAMAGE_RADIUS );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
WeaponSound( SPECIAL1 );
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
m_bRedraw = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,330 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "in_buttons.h"
|
||||
#include "takedamageinfo.h"
|
||||
#include "ammodef.h"
|
||||
#include "hl2mp_gamerules.h"
|
||||
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
extern IVModelInfoClient* modelinfo;
|
||||
#else
|
||||
extern IVModelInfo* modelinfo;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#include "vgui/ISurface.h"
|
||||
#include "vgui_controls/Controls.h"
|
||||
#include "c_hl2mp_player.h"
|
||||
#include "hud_crosshair.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "hl2mp_player.h"
|
||||
#include "vphysics/constraints.h"
|
||||
|
||||
#endif
|
||||
|
||||
#include "weapon_hl2mpbase.h"
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- //
|
||||
// Global functions.
|
||||
// ----------------------------------------------------------------------------- //
|
||||
|
||||
bool IsAmmoType( int iAmmoType, const char *pAmmoName )
|
||||
{
|
||||
return GetAmmoDef()->Index( pAmmoName ) == iAmmoType;
|
||||
}
|
||||
|
||||
static const char * s_WeaponAliasInfo[] =
|
||||
{
|
||||
"none", // WEAPON_NONE = 0,
|
||||
|
||||
//Melee
|
||||
"shotgun", //WEAPON_AMERKNIFE,
|
||||
|
||||
NULL, // end of list marker
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- //
|
||||
// CWeaponHL2MPBase tables.
|
||||
// ----------------------------------------------------------------------------- //
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponHL2MPBase, DT_WeaponHL2MPBase )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponHL2MPBase, DT_WeaponHL2MPBase )
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#else
|
||||
// world weapon models have no aminations
|
||||
// SendPropExclude( "DT_AnimTimeMustBeFirst", "m_flAnimTime" ),
|
||||
// SendPropExclude( "DT_BaseAnimating", "m_nSequence" ),
|
||||
// SendPropExclude( "DT_LocalActiveWeaponData", "m_flTimeWeaponIdle" ),
|
||||
#endif
|
||||
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponHL2MPBase )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_hl2mp_base, CWeaponHL2MPBase );
|
||||
|
||||
|
||||
#ifdef GAME_DLL
|
||||
|
||||
BEGIN_DATADESC( CWeaponHL2MPBase )
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------- //
|
||||
// CWeaponHL2MPBase implementation.
|
||||
// ----------------------------------------------------------------------------- //
|
||||
CWeaponHL2MPBase::CWeaponHL2MPBase()
|
||||
{
|
||||
SetPredictionEligible( true );
|
||||
AddSolidFlags( FSOLID_TRIGGER ); // Nothing collides with these but it gets touches.
|
||||
|
||||
m_flNextResetCheckTime = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponHL2MPBase::IsPredicted() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWeaponHL2MPBase::WeaponSound( WeaponSound_t sound_type, float soundtime /* = 0.0f */ )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
// If we have some sounds from the weapon classname.txt file, play a random one of them
|
||||
const char *shootsound = GetWpnData().aShootSounds[ sound_type ];
|
||||
if ( !shootsound || !shootsound[0] )
|
||||
return;
|
||||
|
||||
CBroadcastRecipientFilter filter; // this is client side only
|
||||
if ( !te->CanPredict() )
|
||||
return;
|
||||
|
||||
CBaseEntity::EmitSound( filter, GetPlayerOwner()->entindex(), shootsound, &GetPlayerOwner()->GetAbsOrigin() );
|
||||
#else
|
||||
BaseClass::WeaponSound( sound_type, soundtime );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
CBasePlayer* CWeaponHL2MPBase::GetPlayerOwner() const
|
||||
{
|
||||
return dynamic_cast< CBasePlayer* >( GetOwner() );
|
||||
}
|
||||
|
||||
CHL2MP_Player* CWeaponHL2MPBase::GetHL2MPPlayerOwner() const
|
||||
{
|
||||
return dynamic_cast< CHL2MP_Player* >( GetOwner() );
|
||||
}
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
void CWeaponHL2MPBase::OnDataChanged( DataUpdateType_t type )
|
||||
{
|
||||
BaseClass::OnDataChanged( type );
|
||||
|
||||
if ( GetPredictable() && !ShouldPredict() )
|
||||
ShutdownPredictable();
|
||||
}
|
||||
|
||||
|
||||
bool CWeaponHL2MPBase::ShouldPredict()
|
||||
{
|
||||
if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() )
|
||||
return true;
|
||||
|
||||
return BaseClass::ShouldPredict();
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
void CWeaponHL2MPBase::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
|
||||
// Set this here to allow players to shoot dropped weapons
|
||||
SetCollisionGroup( COLLISION_GROUP_WEAPON );
|
||||
}
|
||||
|
||||
void CWeaponHL2MPBase::Materialize( void )
|
||||
{
|
||||
if ( IsEffectActive( EF_NODRAW ) )
|
||||
{
|
||||
// changing from invisible state to visible.
|
||||
EmitSound( "AlyxEmp.Charge" );
|
||||
|
||||
RemoveEffects( EF_NODRAW );
|
||||
DoMuzzleFlash();
|
||||
}
|
||||
|
||||
if ( HasSpawnFlags( SF_NORESPAWN ) == false )
|
||||
{
|
||||
VPhysicsInitNormal( SOLID_BBOX, GetSolidFlags() | FSOLID_TRIGGER, false );
|
||||
SetMoveType( MOVETYPE_VPHYSICS );
|
||||
|
||||
HL2MPRules()->AddLevelDesignerPlacedObject( this );
|
||||
}
|
||||
|
||||
if ( HasSpawnFlags( SF_NORESPAWN ) == false )
|
||||
{
|
||||
if ( GetOriginalSpawnOrigin() == vec3_origin )
|
||||
{
|
||||
m_vOriginalSpawnOrigin = GetAbsOrigin();
|
||||
m_vOriginalSpawnAngles = GetAbsAngles();
|
||||
}
|
||||
}
|
||||
|
||||
SetPickupTouch();
|
||||
|
||||
SetThink (NULL);
|
||||
}
|
||||
|
||||
int CWeaponHL2MPBase::ObjectCaps()
|
||||
{
|
||||
return BaseClass::ObjectCaps() & ~FCAP_IMPULSE_USE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void CWeaponHL2MPBase::FallInit( void )
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
SetModel( GetWorldModel() );
|
||||
VPhysicsDestroyObject();
|
||||
|
||||
if ( HasSpawnFlags( SF_NORESPAWN ) == false )
|
||||
{
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
SetSolid( SOLID_BBOX );
|
||||
AddSolidFlags( FSOLID_TRIGGER );
|
||||
|
||||
UTIL_DropToFloor( this, MASK_SOLID );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !VPhysicsInitNormal( SOLID_BBOX, GetSolidFlags() | FSOLID_TRIGGER, false ) )
|
||||
{
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
SetSolid( SOLID_BBOX );
|
||||
AddSolidFlags( FSOLID_TRIGGER );
|
||||
}
|
||||
else
|
||||
{
|
||||
#if !defined( CLIENT_DLL )
|
||||
// Constrained start?
|
||||
if ( HasSpawnFlags( SF_WEAPON_START_CONSTRAINED ) )
|
||||
{
|
||||
//Constrain the weapon in place
|
||||
IPhysicsObject *pReferenceObject, *pAttachedObject;
|
||||
|
||||
pReferenceObject = g_PhysWorldObject;
|
||||
pAttachedObject = VPhysicsGetObject();
|
||||
|
||||
if ( pReferenceObject && pAttachedObject )
|
||||
{
|
||||
constraint_fixedparams_t fixed;
|
||||
fixed.Defaults();
|
||||
fixed.InitWithCurrentObjectState( pReferenceObject, pAttachedObject );
|
||||
|
||||
fixed.constraint.forceLimit = lbs2kg( 10000 );
|
||||
fixed.constraint.torqueLimit = lbs2kg( 10000 );
|
||||
|
||||
IPhysicsConstraint *pConstraint = GetConstraint();
|
||||
|
||||
pConstraint = physenv->CreateFixedConstraint( pReferenceObject, pAttachedObject, NULL, fixed );
|
||||
|
||||
pConstraint->SetGameData( (void *) this );
|
||||
}
|
||||
}
|
||||
#endif //CLIENT_DLL
|
||||
}
|
||||
}
|
||||
|
||||
SetPickupTouch();
|
||||
|
||||
SetThink( &CBaseCombatWeapon::FallThink );
|
||||
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
const CHL2MPSWeaponInfo &CWeaponHL2MPBase::GetHL2MPWpnData() const
|
||||
{
|
||||
const FileWeaponInfo_t *pWeaponInfo = &GetWpnData();
|
||||
const CHL2MPSWeaponInfo *pHL2MPInfo;
|
||||
|
||||
#ifdef _DEBUG
|
||||
pHL2MPInfo = dynamic_cast< const CHL2MPSWeaponInfo* >( pWeaponInfo );
|
||||
Assert( pHL2MPInfo );
|
||||
#else
|
||||
pHL2MPInfo = static_cast< const CHL2MPSWeaponInfo* >( pWeaponInfo );
|
||||
#endif
|
||||
|
||||
return *pHL2MPInfo;
|
||||
}
|
||||
void CWeaponHL2MPBase::FireBullets( const FireBulletsInfo_t &info )
|
||||
{
|
||||
FireBulletsInfo_t modinfo = info;
|
||||
|
||||
modinfo.m_iPlayerDamage = GetHL2MPWpnData().m_iPlayerDamage;
|
||||
|
||||
BaseClass::FireBullets( modinfo );
|
||||
}
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#include "c_te_effect_dispatch.h"
|
||||
|
||||
#define NUM_MUZZLE_FLASH_TYPES 4
|
||||
|
||||
bool CWeaponHL2MPBase::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
|
||||
{
|
||||
return BaseClass::OnFireEvent( pViewModel, origin, angles, event, options );
|
||||
}
|
||||
|
||||
|
||||
void UTIL_ClipPunchAngleOffset( QAngle &in, const QAngle &punch, const QAngle &clip )
|
||||
{
|
||||
QAngle final = in + punch;
|
||||
|
||||
//Clip each component
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
if ( final[i] > clip[i] )
|
||||
{
|
||||
final[i] = clip[i];
|
||||
}
|
||||
else if ( final[i] < -clip[i] )
|
||||
{
|
||||
final[i] = -clip[i];
|
||||
}
|
||||
|
||||
//Return the result
|
||||
in[i] = final[i] - punch[i];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef WEAPON_HL2MPBASE_H
|
||||
#define WEAPON_HL2MPBASE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "hl2mp_player_shared.h"
|
||||
#include "basecombatweapon_shared.h"
|
||||
#include "hl2mp_weapon_parse.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CWeaponHL2MPBase C_WeaponHL2MPBase
|
||||
void UTIL_ClipPunchAngleOffset( QAngle &in, const QAngle &punch, const QAngle &clip );
|
||||
#endif
|
||||
|
||||
class CHL2MP_Player;
|
||||
|
||||
// These are the names of the ammo types that go in the CAmmoDefs and that the
|
||||
// weapon script files reference.
|
||||
|
||||
// Given an ammo type (like from a weapon's GetPrimaryAmmoType()), this compares it
|
||||
// against the ammo name you specify.
|
||||
// MIKETODO: this should use indexing instead of searching and strcmp()'ing all the time.
|
||||
bool IsAmmoType( int iAmmoType, const char *pAmmoName );
|
||||
|
||||
class CWeaponHL2MPBase : public CBaseCombatWeapon
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponHL2MPBase, CBaseCombatWeapon );
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CWeaponHL2MPBase();
|
||||
|
||||
#ifdef GAME_DLL
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void SendReloadSoundEvent( void );
|
||||
|
||||
void Materialize( void );
|
||||
virtual int ObjectCaps( void );
|
||||
#endif
|
||||
|
||||
// All predicted weapons need to implement and return true
|
||||
virtual bool IsPredicted() const;
|
||||
|
||||
CBasePlayer* GetPlayerOwner() const;
|
||||
CHL2MP_Player* GetHL2MPPlayerOwner() const;
|
||||
|
||||
void WeaponSound( WeaponSound_t sound_type, float soundtime = 0.0f );
|
||||
|
||||
CHL2MPSWeaponInfo const &GetHL2MPWpnData() const;
|
||||
|
||||
|
||||
virtual void FireBullets( const FireBulletsInfo_t &info );
|
||||
virtual void FallInit( void );
|
||||
|
||||
public:
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
virtual bool ShouldPredict();
|
||||
virtual void OnDataChanged( DataUpdateType_t type );
|
||||
|
||||
virtual bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options );
|
||||
|
||||
#else
|
||||
|
||||
virtual void Spawn();
|
||||
|
||||
#endif
|
||||
|
||||
float m_flPrevAnimTime;
|
||||
float m_flNextResetCheckTime;
|
||||
|
||||
Vector GetOriginalSpawnOrigin( void ) { return m_vOriginalSpawnOrigin; }
|
||||
QAngle GetOriginalSpawnAngles( void ) { return m_vOriginalSpawnAngles; }
|
||||
|
||||
private:
|
||||
|
||||
CWeaponHL2MPBase( const CWeaponHL2MPBase & );
|
||||
|
||||
Vector m_vOriginalSpawnOrigin;
|
||||
QAngle m_vOriginalSpawnAngles;
|
||||
};
|
||||
|
||||
|
||||
#endif // WEAPON_HL2MPBASE_H
|
||||
@@ -0,0 +1,242 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#include "c_hl2mp_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#endif
|
||||
|
||||
#include "weapon_hl2mpbase_machinegun.h"
|
||||
#include "in_buttons.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( HL2MPMachineGun, DT_HL2MPMachineGun )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CHL2MPMachineGun, DT_HL2MPMachineGun )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CHL2MPMachineGun )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
//=========================================================
|
||||
// >> CHLSelectFireMachineGun
|
||||
//=========================================================
|
||||
BEGIN_DATADESC( CHL2MPMachineGun )
|
||||
|
||||
DEFINE_FIELD( m_nShotsFired, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_flNextSoundTime, FIELD_TIME ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CHL2MPMachineGun::CHL2MPMachineGun( void )
|
||||
{
|
||||
}
|
||||
|
||||
const Vector &CHL2MPMachineGun::GetBulletSpread( void )
|
||||
{
|
||||
static Vector cone = VECTOR_CONE_3DEGREES;
|
||||
return cone;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHL2MPMachineGun::PrimaryAttack( void )
|
||||
{
|
||||
// Only the player fires this way so we can cast
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
if (!pPlayer)
|
||||
return;
|
||||
|
||||
// Abort here to handle burst and auto fire modes
|
||||
if ( (UsesClipsForAmmo1() && m_iClip1 == 0) || ( !UsesClipsForAmmo1() && !pPlayer->GetAmmoCount(m_iPrimaryAmmoType) ) )
|
||||
return;
|
||||
|
||||
m_nShotsFired++;
|
||||
|
||||
pPlayer->DoMuzzleFlash();
|
||||
|
||||
// To make the firing framerate independent, we may have to fire more than one bullet here on low-framerate systems,
|
||||
// especially if the weapon we're firing has a really fast rate of fire.
|
||||
int iBulletsToFire = 0;
|
||||
float fireRate = GetFireRate();
|
||||
|
||||
while ( m_flNextPrimaryAttack <= gpGlobals->curtime )
|
||||
{
|
||||
// MUST call sound before removing a round from the clip of a CHLMachineGun
|
||||
WeaponSound(SINGLE, m_flNextPrimaryAttack);
|
||||
m_flNextPrimaryAttack = m_flNextPrimaryAttack + fireRate;
|
||||
iBulletsToFire++;
|
||||
}
|
||||
|
||||
// Make sure we don't fire more than the amount in the clip, if this weapon uses clips
|
||||
if ( UsesClipsForAmmo1() )
|
||||
{
|
||||
if ( iBulletsToFire > m_iClip1 )
|
||||
iBulletsToFire = m_iClip1;
|
||||
m_iClip1 -= iBulletsToFire;
|
||||
}
|
||||
|
||||
CHL2MP_Player *pHL2MPPlayer = ToHL2MPPlayer( pPlayer );
|
||||
|
||||
// Fire the bullets
|
||||
FireBulletsInfo_t info;
|
||||
info.m_iShots = iBulletsToFire;
|
||||
info.m_vecSrc = pHL2MPPlayer->Weapon_ShootPosition( );
|
||||
info.m_vecDirShooting = pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
|
||||
info.m_vecSpread = pHL2MPPlayer->GetAttackSpread( this );
|
||||
info.m_flDistance = MAX_TRACE_LENGTH;
|
||||
info.m_iAmmoType = m_iPrimaryAmmoType;
|
||||
info.m_iTracerFreq = 2;
|
||||
FireBullets( info );
|
||||
|
||||
//Factor in the view kick
|
||||
AddViewKick();
|
||||
|
||||
if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
|
||||
{
|
||||
// HEV suit - indicate out of ammo condition
|
||||
pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
|
||||
}
|
||||
|
||||
SendWeaponAnim( GetPrimaryAttackActivity() );
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &info -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHL2MPMachineGun::FireBullets( const FireBulletsInfo_t &info )
|
||||
{
|
||||
if(CBasePlayer *pPlayer = ToBasePlayer ( GetOwner() ) )
|
||||
{
|
||||
pPlayer->FireBullets(info);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHL2MPMachineGun::DoMachineGunKick( CBasePlayer *pPlayer, float dampEasy, float maxVerticleKickAngle, float fireDurationTime, float slideLimitTime )
|
||||
{
|
||||
#define KICK_MIN_X 0.2f //Degrees
|
||||
#define KICK_MIN_Y 0.2f //Degrees
|
||||
#define KICK_MIN_Z 0.1f //Degrees
|
||||
|
||||
QAngle vecScratch;
|
||||
int iSeed = CBaseEntity::GetPredictionRandomSeed() & 255;
|
||||
|
||||
//Find how far into our accuracy degradation we are
|
||||
float duration = ( fireDurationTime > slideLimitTime ) ? slideLimitTime : fireDurationTime;
|
||||
float kickPerc = duration / slideLimitTime;
|
||||
|
||||
// do this to get a hard discontinuity, clear out anything under 10 degrees punch
|
||||
pPlayer->ViewPunchReset( 10 );
|
||||
|
||||
//Apply this to the view angles as well
|
||||
vecScratch.x = -( KICK_MIN_X + ( maxVerticleKickAngle * kickPerc ) );
|
||||
vecScratch.y = -( KICK_MIN_Y + ( maxVerticleKickAngle * kickPerc ) ) / 3;
|
||||
vecScratch.z = KICK_MIN_Z + ( maxVerticleKickAngle * kickPerc ) / 8;
|
||||
|
||||
RandomSeed( iSeed );
|
||||
|
||||
//Wibble left and right
|
||||
if ( RandomInt( -1, 1 ) >= 0 )
|
||||
vecScratch.y *= -1;
|
||||
|
||||
iSeed++;
|
||||
|
||||
//Wobble up and down
|
||||
if ( RandomInt( -1, 1 ) >= 0 )
|
||||
vecScratch.z *= -1;
|
||||
|
||||
//Clip this to our desired min/max
|
||||
UTIL_ClipPunchAngleOffset( vecScratch, pPlayer->m_Local.m_vecPunchAngle, QAngle( 24.0f, 3.0f, 1.0f ) );
|
||||
|
||||
//Add it to the view punch
|
||||
// NOTE: 0.5 is just tuned to match the old effect before the punch became simulated
|
||||
pPlayer->ViewPunch( vecScratch * 0.5 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reset our shots fired
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CHL2MPMachineGun::Deploy( void )
|
||||
{
|
||||
m_nShotsFired = 0;
|
||||
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Make enough sound events to fill the estimated think interval
|
||||
// returns: number of shots needed
|
||||
//-----------------------------------------------------------------------------
|
||||
int CHL2MPMachineGun::WeaponSoundRealtime( WeaponSound_t shoot_type )
|
||||
{
|
||||
int numBullets = 0;
|
||||
|
||||
// ran out of time, clamp to current
|
||||
if (m_flNextSoundTime < gpGlobals->curtime)
|
||||
{
|
||||
m_flNextSoundTime = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
// make enough sound events to fill up the next estimated think interval
|
||||
float dt = clamp( m_flAnimTime - m_flPrevAnimTime, 0, 0.2 );
|
||||
if (m_flNextSoundTime < gpGlobals->curtime + dt)
|
||||
{
|
||||
WeaponSound( SINGLE_NPC, m_flNextSoundTime );
|
||||
m_flNextSoundTime += GetFireRate();
|
||||
numBullets++;
|
||||
}
|
||||
if (m_flNextSoundTime < gpGlobals->curtime + dt)
|
||||
{
|
||||
WeaponSound( SINGLE_NPC, m_flNextSoundTime );
|
||||
m_flNextSoundTime += GetFireRate();
|
||||
numBullets++;
|
||||
}
|
||||
|
||||
return numBullets;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHL2MPMachineGun::ItemPostFrame( void )
|
||||
{
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pOwner == NULL )
|
||||
return;
|
||||
|
||||
// Debounce the recoiling counter
|
||||
if ( ( pOwner->m_nButtons & IN_ATTACK ) == false )
|
||||
{
|
||||
m_nShotsFired = 0;
|
||||
}
|
||||
|
||||
BaseClass::ItemPostFrame();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "weapon_hl2mpbase.h"
|
||||
|
||||
#ifndef BASEHLCOMBATWEAPON_H
|
||||
#define BASEHLCOMBATWEAPON_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CHL2MPMachineGun C_HL2MPMachineGun
|
||||
#endif
|
||||
|
||||
//=========================================================
|
||||
// Machine gun base class
|
||||
//=========================================================
|
||||
class CHL2MPMachineGun : public CWeaponHL2MPBase
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CHL2MPMachineGun, CWeaponHL2MPBase );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
CHL2MPMachineGun();
|
||||
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
void PrimaryAttack( void );
|
||||
|
||||
// Default calls through to m_hOwner, but plasma weapons can override and shoot projectiles here.
|
||||
virtual void ItemPostFrame( void );
|
||||
virtual void FireBullets( const FireBulletsInfo_t &info );
|
||||
virtual bool Deploy( void );
|
||||
|
||||
virtual const Vector &GetBulletSpread( void );
|
||||
|
||||
int WeaponSoundRealtime( WeaponSound_t shoot_type );
|
||||
|
||||
// utility function
|
||||
static void DoMachineGunKick( CBasePlayer *pPlayer, float dampEasy, float maxVerticleKickAngle, float fireDurationTime, float slideLimitTime );
|
||||
|
||||
private:
|
||||
|
||||
CHL2MPMachineGun( const CHL2MPMachineGun & );
|
||||
|
||||
protected:
|
||||
|
||||
int m_nShotsFired; // Number of consecutive shots fired
|
||||
|
||||
float m_flNextSoundTime; // real-time clock of when to make next sound
|
||||
};
|
||||
|
||||
#endif // BASEHLCOMBATWEAPON_H
|
||||
@@ -0,0 +1,363 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_hl2mpbasebasebludgeon.h"
|
||||
#include "gamerules.h"
|
||||
#include "ammodef.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
#include "in_buttons.h"
|
||||
#include "animation.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#include "c_hl2mp_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "ndebugoverlay.h"
|
||||
#include "te_effect_dispatch.h"
|
||||
#include "ilagcompensationmanager.h"
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( BaseHL2MPBludgeonWeapon, DT_BaseHL2MPBludgeonWeapon )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CBaseHL2MPBludgeonWeapon, DT_BaseHL2MPBludgeonWeapon )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CBaseHL2MPBludgeonWeapon )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
#define BLUDGEON_HULL_DIM 16
|
||||
|
||||
static const Vector g_bludgeonMins(-BLUDGEON_HULL_DIM,-BLUDGEON_HULL_DIM,-BLUDGEON_HULL_DIM);
|
||||
static const Vector g_bludgeonMaxs(BLUDGEON_HULL_DIM,BLUDGEON_HULL_DIM,BLUDGEON_HULL_DIM);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseHL2MPBludgeonWeapon::CBaseHL2MPBludgeonWeapon()
|
||||
{
|
||||
m_bFiresUnderwater = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Spawn the weapon
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseHL2MPBludgeonWeapon::Spawn( void )
|
||||
{
|
||||
m_fMinRange1 = 0;
|
||||
m_fMinRange2 = 0;
|
||||
m_fMaxRange1 = 64;
|
||||
m_fMaxRange2 = 64;
|
||||
//Call base class first
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Precache the weapon
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseHL2MPBludgeonWeapon::Precache( void )
|
||||
{
|
||||
//Call base class first
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose : Update weapon
|
||||
//------------------------------------------------------------------------------
|
||||
void CBaseHL2MPBludgeonWeapon::ItemPostFrame( void )
|
||||
{
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pOwner == NULL )
|
||||
return;
|
||||
|
||||
if ( (pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
|
||||
{
|
||||
PrimaryAttack();
|
||||
}
|
||||
else if ( (pOwner->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime) )
|
||||
{
|
||||
SecondaryAttack();
|
||||
}
|
||||
else
|
||||
{
|
||||
WeaponIdle();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose :
|
||||
// Input :
|
||||
// Output :
|
||||
//------------------------------------------------------------------------------
|
||||
void CBaseHL2MPBludgeonWeapon::PrimaryAttack()
|
||||
{
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
CHL2MP_Player *pPlayer = ToHL2MPPlayer( GetPlayerOwner() );
|
||||
// Move other players back to history positions based on local player's lag
|
||||
lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() );
|
||||
#endif
|
||||
Swing( false );
|
||||
#ifndef CLIENT_DLL
|
||||
// Move other players back to history positions based on local player's lag
|
||||
lagcompensation->FinishLagCompensation( pPlayer );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose :
|
||||
// Input :
|
||||
// Output :
|
||||
//------------------------------------------------------------------------------
|
||||
void CBaseHL2MPBludgeonWeapon::SecondaryAttack()
|
||||
{
|
||||
Swing( true );
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose: Implement impact function
|
||||
//------------------------------------------------------------------------------
|
||||
void CBaseHL2MPBludgeonWeapon::Hit( trace_t &traceHit, Activity nHitActivity )
|
||||
{
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
|
||||
//Do view kick
|
||||
// AddViewKick();
|
||||
|
||||
CBaseEntity *pHitEntity = traceHit.m_pEnt;
|
||||
|
||||
//Apply damage to a hit target
|
||||
if ( pHitEntity != NULL )
|
||||
{
|
||||
Vector hitDirection;
|
||||
pPlayer->EyeVectors( &hitDirection, NULL, NULL );
|
||||
VectorNormalize( hitDirection );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
CTakeDamageInfo info( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB );
|
||||
|
||||
if( pPlayer && pHitEntity->IsNPC() )
|
||||
{
|
||||
// If bonking an NPC, adjust damage.
|
||||
info.AdjustPlayerDamageInflictedForSkillLevel();
|
||||
}
|
||||
|
||||
CalculateMeleeDamageForce( &info, hitDirection, traceHit.endpos );
|
||||
|
||||
pHitEntity->DispatchTraceAttack( info, hitDirection, &traceHit );
|
||||
ApplyMultiDamage();
|
||||
|
||||
// Now hit all triggers along the ray that...
|
||||
TraceAttackToTriggers( info, traceHit.startpos, traceHit.endpos, hitDirection );
|
||||
#endif
|
||||
WeaponSound( MELEE_HIT );
|
||||
}
|
||||
|
||||
// Apply an impact effect
|
||||
ImpactEffect( traceHit );
|
||||
}
|
||||
|
||||
Activity CBaseHL2MPBludgeonWeapon::ChooseIntersectionPointAndActivity( trace_t &hitTrace, const Vector &mins, const Vector &maxs, CBasePlayer *pOwner )
|
||||
{
|
||||
int i, j, k;
|
||||
float distance;
|
||||
const float *minmaxs[2] = {mins.Base(), maxs.Base()};
|
||||
trace_t tmpTrace;
|
||||
Vector vecHullEnd = hitTrace.endpos;
|
||||
Vector vecEnd;
|
||||
|
||||
distance = 1e6f;
|
||||
Vector vecSrc = hitTrace.startpos;
|
||||
|
||||
vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2);
|
||||
UTIL_TraceLine( vecSrc, vecHullEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &tmpTrace );
|
||||
if ( tmpTrace.fraction == 1.0 )
|
||||
{
|
||||
for ( i = 0; i < 2; i++ )
|
||||
{
|
||||
for ( j = 0; j < 2; j++ )
|
||||
{
|
||||
for ( k = 0; k < 2; k++ )
|
||||
{
|
||||
vecEnd.x = vecHullEnd.x + minmaxs[i][0];
|
||||
vecEnd.y = vecHullEnd.y + minmaxs[j][1];
|
||||
vecEnd.z = vecHullEnd.z + minmaxs[k][2];
|
||||
|
||||
UTIL_TraceLine( vecSrc, vecEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &tmpTrace );
|
||||
if ( tmpTrace.fraction < 1.0 )
|
||||
{
|
||||
float thisDistance = (tmpTrace.endpos - vecSrc).Length();
|
||||
if ( thisDistance < distance )
|
||||
{
|
||||
hitTrace = tmpTrace;
|
||||
distance = thisDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hitTrace = tmpTrace;
|
||||
}
|
||||
|
||||
|
||||
return ACT_VM_HITCENTER;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &traceHit -
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseHL2MPBludgeonWeapon::ImpactWater( const Vector &start, const Vector &end )
|
||||
{
|
||||
//FIXME: This doesn't handle the case of trying to splash while being underwater, but that's not going to look good
|
||||
// right now anyway...
|
||||
|
||||
// We must start outside the water
|
||||
if ( UTIL_PointContents( start ) & (CONTENTS_WATER|CONTENTS_SLIME))
|
||||
return false;
|
||||
|
||||
// We must end inside of water
|
||||
if ( !(UTIL_PointContents( end ) & (CONTENTS_WATER|CONTENTS_SLIME)))
|
||||
return false;
|
||||
|
||||
trace_t waterTrace;
|
||||
|
||||
UTIL_TraceLine( start, end, (CONTENTS_WATER|CONTENTS_SLIME), GetOwner(), COLLISION_GROUP_NONE, &waterTrace );
|
||||
|
||||
if ( waterTrace.fraction < 1.0f )
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
CEffectData data;
|
||||
|
||||
data.m_fFlags = 0;
|
||||
data.m_vOrigin = waterTrace.endpos;
|
||||
data.m_vNormal = waterTrace.plane.normal;
|
||||
data.m_flScale = 8.0f;
|
||||
|
||||
// See if we hit slime
|
||||
if ( waterTrace.contents & CONTENTS_SLIME )
|
||||
{
|
||||
data.m_fFlags |= FX_WATER_IN_SLIME;
|
||||
}
|
||||
|
||||
DispatchEffect( "watersplash", data );
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseHL2MPBludgeonWeapon::ImpactEffect( trace_t &traceHit )
|
||||
{
|
||||
// See if we hit water (we don't do the other impact effects in this case)
|
||||
if ( ImpactWater( traceHit.startpos, traceHit.endpos ) )
|
||||
return;
|
||||
|
||||
//FIXME: need new decals
|
||||
UTIL_ImpactTrace( &traceHit, DMG_CLUB );
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose : Starts the swing of the weapon and determines the animation
|
||||
// Input : bIsSecondary - is this a secondary attack?
|
||||
//------------------------------------------------------------------------------
|
||||
void CBaseHL2MPBludgeonWeapon::Swing( int bIsSecondary )
|
||||
{
|
||||
trace_t traceHit;
|
||||
|
||||
// Try a ray
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
if ( !pOwner )
|
||||
return;
|
||||
|
||||
Vector swingStart = pOwner->Weapon_ShootPosition( );
|
||||
Vector forward;
|
||||
|
||||
pOwner->EyeVectors( &forward, NULL, NULL );
|
||||
|
||||
Vector swingEnd = swingStart + forward * GetRange();
|
||||
UTIL_TraceLine( swingStart, swingEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit );
|
||||
Activity nHitActivity = ACT_VM_HITCENTER;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// Like bullets, bludgeon traces have to trace against triggers.
|
||||
CTakeDamageInfo triggerInfo( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB );
|
||||
TraceAttackToTriggers( triggerInfo, traceHit.startpos, traceHit.endpos, vec3_origin );
|
||||
#endif
|
||||
|
||||
if ( traceHit.fraction == 1.0 )
|
||||
{
|
||||
float bludgeonHullRadius = 1.732f * BLUDGEON_HULL_DIM; // hull is +/- 16, so use cuberoot of 2 to determine how big the hull is from center to the corner point
|
||||
|
||||
// Back off by hull "radius"
|
||||
swingEnd -= forward * bludgeonHullRadius;
|
||||
|
||||
UTIL_TraceHull( swingStart, swingEnd, g_bludgeonMins, g_bludgeonMaxs, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit );
|
||||
if ( traceHit.fraction < 1.0 && traceHit.m_pEnt )
|
||||
{
|
||||
Vector vecToTarget = traceHit.m_pEnt->GetAbsOrigin() - swingStart;
|
||||
VectorNormalize( vecToTarget );
|
||||
|
||||
float dot = vecToTarget.Dot( forward );
|
||||
|
||||
// YWB: Make sure they are sort of facing the guy at least...
|
||||
if ( dot < 0.70721f )
|
||||
{
|
||||
// Force amiss
|
||||
traceHit.fraction = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
nHitActivity = ChooseIntersectionPointAndActivity( traceHit, g_bludgeonMins, g_bludgeonMaxs, pOwner );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WeaponSound( SINGLE );
|
||||
|
||||
// -------------------------
|
||||
// Miss
|
||||
// -------------------------
|
||||
if ( traceHit.fraction == 1.0f )
|
||||
{
|
||||
nHitActivity = bIsSecondary ? ACT_VM_MISSCENTER2 : ACT_VM_MISSCENTER;
|
||||
|
||||
// We want to test the first swing again
|
||||
Vector testEnd = swingStart + forward * GetRange();
|
||||
|
||||
// See if we happened to hit water
|
||||
ImpactWater( swingStart, testEnd );
|
||||
}
|
||||
else
|
||||
{
|
||||
Hit( traceHit, nHitActivity );
|
||||
}
|
||||
|
||||
// Send the anim
|
||||
SendWeaponAnim( nHitActivity );
|
||||
|
||||
pOwner->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
//Setup our next attack times
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: The class from which all bludgeon melee
|
||||
// weapons are derived.
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
|
||||
#ifndef BASEBLUDGEONWEAPON_H
|
||||
#define BASEBLUDGEONWEAPON_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CBaseHL2MPBludgeonWeapon C_BaseHL2MPBludgeonWeapon
|
||||
#endif
|
||||
|
||||
//=========================================================
|
||||
// CBaseHLBludgeonWeapon
|
||||
//=========================================================
|
||||
class CBaseHL2MPBludgeonWeapon : public CBaseHL2MPCombatWeapon
|
||||
{
|
||||
DECLARE_CLASS( CBaseHL2MPBludgeonWeapon, CBaseHL2MPCombatWeapon );
|
||||
public:
|
||||
CBaseHL2MPBludgeonWeapon();
|
||||
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void Precache( void );
|
||||
|
||||
//Attack functions
|
||||
virtual void PrimaryAttack( void );
|
||||
virtual void SecondaryAttack( void );
|
||||
|
||||
virtual void ItemPostFrame( void );
|
||||
|
||||
//Functions to select animation sequences
|
||||
virtual Activity GetPrimaryAttackActivity( void ) { return ACT_VM_HITCENTER; }
|
||||
virtual Activity GetSecondaryAttackActivity( void ) { return ACT_VM_HITCENTER2; }
|
||||
|
||||
virtual float GetFireRate( void ) { return 0.2f; }
|
||||
virtual float GetRange( void ) { return 32.0f; }
|
||||
virtual float GetDamageForActivity( Activity hitActivity ) { return 1.0f; }
|
||||
|
||||
CBaseHL2MPBludgeonWeapon( const CBaseHL2MPBludgeonWeapon & );
|
||||
|
||||
protected:
|
||||
virtual void ImpactEffect( trace_t &trace );
|
||||
|
||||
private:
|
||||
bool ImpactWater( const Vector &start, const Vector &end );
|
||||
void Swing( int bIsSecondary );
|
||||
void Hit( trace_t &traceHit, Activity nHitActivity );
|
||||
Activity ChooseIntersectionPointAndActivity( trace_t &hitTrace, const Vector &mins, const Vector &maxs, CBasePlayer *pOwner );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,416 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
|
||||
#include "hl2mp_player_shared.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
LINK_ENTITY_TO_CLASS( basehl2mpcombatweapon, CBaseHL2MPCombatWeapon );
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( BaseHL2MPCombatWeapon , DT_BaseHL2MPCombatWeapon )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CBaseHL2MPCombatWeapon , DT_BaseHL2MPCombatWeapon )
|
||||
#if !defined( CLIENT_DLL )
|
||||
// SendPropInt( SENDINFO( m_bReflectViewModelAnimations ), 1, SPROP_UNSIGNED ),
|
||||
#else
|
||||
// RecvPropInt( RECVINFO( m_bReflectViewModelAnimations ) ),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
|
||||
#include "globalstate.h"
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Save/Restore
|
||||
//---------------------------------------------------------
|
||||
BEGIN_DATADESC( CBaseHL2MPCombatWeapon )
|
||||
|
||||
DEFINE_FIELD( m_bLowered, FIELD_BOOLEAN ),
|
||||
DEFINE_FIELD( m_flRaiseTime, FIELD_TIME ),
|
||||
DEFINE_FIELD( m_flHolsterTime, FIELD_TIME ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
#endif
|
||||
|
||||
BEGIN_PREDICTION_DATA( CBaseHL2MPCombatWeapon )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
extern ConVar sk_auto_reload_time;
|
||||
|
||||
CBaseHL2MPCombatWeapon::CBaseHL2MPCombatWeapon( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseHL2MPCombatWeapon::ItemHolsterFrame( void )
|
||||
{
|
||||
BaseClass::ItemHolsterFrame();
|
||||
|
||||
// Must be player held
|
||||
if ( GetOwner() && GetOwner()->IsPlayer() == false )
|
||||
return;
|
||||
|
||||
// We can't be active
|
||||
if ( GetOwner()->GetActiveWeapon() == this )
|
||||
return;
|
||||
|
||||
// If it's been longer than three seconds, reload
|
||||
if ( ( gpGlobals->curtime - m_flHolsterTime ) > sk_auto_reload_time.GetFloat() )
|
||||
{
|
||||
// Just load the clip with no animations
|
||||
FinishReload();
|
||||
m_flHolsterTime = gpGlobals->curtime;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Drops the weapon into a lowered pose
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseHL2MPCombatWeapon::Lower( void )
|
||||
{
|
||||
//Don't bother if we don't have the animation
|
||||
if ( SelectWeightedSequence( ACT_VM_IDLE_LOWERED ) == ACTIVITY_NOT_AVAILABLE )
|
||||
return false;
|
||||
|
||||
m_bLowered = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Brings the weapon up to the ready position
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseHL2MPCombatWeapon::Ready( void )
|
||||
{
|
||||
//Don't bother if we don't have the animation
|
||||
if ( SelectWeightedSequence( ACT_VM_LOWERED_TO_IDLE ) == ACTIVITY_NOT_AVAILABLE )
|
||||
return false;
|
||||
|
||||
m_bLowered = false;
|
||||
m_flRaiseTime = gpGlobals->curtime + 0.5f;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseHL2MPCombatWeapon::Deploy( void )
|
||||
{
|
||||
// If we should be lowered, deploy in the lowered position
|
||||
// We have to ask the player if the last time it checked, the weapon was lowered
|
||||
if ( GetOwner() && GetOwner()->IsPlayer() )
|
||||
{
|
||||
CHL2MP_Player *pPlayer = assert_cast<CHL2MP_Player*>( GetOwner() );
|
||||
if ( pPlayer->IsWeaponLowered() )
|
||||
{
|
||||
if ( SelectWeightedSequence( ACT_VM_IDLE_LOWERED ) != ACTIVITY_NOT_AVAILABLE )
|
||||
{
|
||||
if ( DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_VM_IDLE_LOWERED, (char*)GetAnimPrefix() ) )
|
||||
{
|
||||
m_bLowered = true;
|
||||
|
||||
// Stomp the next attack time to fix the fact that the lower idles are long
|
||||
pPlayer->SetNextAttack( gpGlobals->curtime + 1.0 );
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 1.0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_bLowered = false;
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseHL2MPCombatWeapon::Holster( CBaseCombatWeapon *pSwitchingTo )
|
||||
{
|
||||
if ( BaseClass::Holster( pSwitchingTo ) )
|
||||
{
|
||||
SetWeaponVisible( false );
|
||||
m_flHolsterTime = gpGlobals->curtime;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseHL2MPCombatWeapon::WeaponShouldBeLowered( void )
|
||||
{
|
||||
// Can't be in the middle of another animation
|
||||
if ( GetIdealActivity() != ACT_VM_IDLE_LOWERED && GetIdealActivity() != ACT_VM_IDLE &&
|
||||
GetIdealActivity() != ACT_VM_IDLE_TO_LOWERED && GetIdealActivity() != ACT_VM_LOWERED_TO_IDLE )
|
||||
return false;
|
||||
|
||||
if ( m_bLowered )
|
||||
return true;
|
||||
|
||||
#if !defined( CLIENT_DLL )
|
||||
|
||||
if ( GlobalEntity_GetState( "friendly_encounter" ) == GLOBAL_ON )
|
||||
return true;
|
||||
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Allows the weapon to choose proper weapon idle animation
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseHL2MPCombatWeapon::WeaponIdle( void )
|
||||
{
|
||||
//See if we should idle high or low
|
||||
if ( WeaponShouldBeLowered() )
|
||||
{
|
||||
// Move to lowered position if we're not there yet
|
||||
if ( GetActivity() != ACT_VM_IDLE_LOWERED && GetActivity() != ACT_VM_IDLE_TO_LOWERED
|
||||
&& GetActivity() != ACT_TRANSITION )
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_IDLE_LOWERED );
|
||||
}
|
||||
else if ( HasWeaponIdleTimeElapsed() )
|
||||
{
|
||||
// Keep idling low
|
||||
SendWeaponAnim( ACT_VM_IDLE_LOWERED );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// See if we need to raise immediately
|
||||
if ( m_flRaiseTime < gpGlobals->curtime && GetActivity() == ACT_VM_IDLE_LOWERED )
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_IDLE );
|
||||
}
|
||||
else if ( HasWeaponIdleTimeElapsed() )
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_IDLE );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
|
||||
#define HL2_BOB_CYCLE_MIN 1.0f
|
||||
#define HL2_BOB_CYCLE_MAX 0.45f
|
||||
#define HL2_BOB 0.002f
|
||||
#define HL2_BOB_UP 0.5f
|
||||
|
||||
extern float g_lateralBob;
|
||||
extern float g_verticalBob;
|
||||
|
||||
static ConVar cl_bobcycle( "cl_bobcycle","0.8" );
|
||||
static ConVar cl_bob( "cl_bob","0.002" );
|
||||
static ConVar cl_bobup( "cl_bobup","0.5" );
|
||||
|
||||
// Register these cvars if needed for easy tweaking
|
||||
static ConVar v_iyaw_cycle( "v_iyaw_cycle", "2", FCVAR_REPLICATED | FCVAR_CHEAT );
|
||||
static ConVar v_iroll_cycle( "v_iroll_cycle", "0.5", FCVAR_REPLICATED | FCVAR_CHEAT );
|
||||
static ConVar v_ipitch_cycle( "v_ipitch_cycle", "1", FCVAR_REPLICATED | FCVAR_CHEAT );
|
||||
static ConVar v_iyaw_level( "v_iyaw_level", "0.3", FCVAR_REPLICATED | FCVAR_CHEAT );
|
||||
static ConVar v_iroll_level( "v_iroll_level", "0.1", FCVAR_REPLICATED | FCVAR_CHEAT );
|
||||
static ConVar v_ipitch_level( "v_ipitch_level", "0.3", FCVAR_REPLICATED | FCVAR_CHEAT );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : float
|
||||
//-----------------------------------------------------------------------------
|
||||
float CBaseHL2MPCombatWeapon::CalcViewmodelBob( void )
|
||||
{
|
||||
static float bobtime;
|
||||
static float lastbobtime;
|
||||
float cycle;
|
||||
|
||||
CBasePlayer *player = ToBasePlayer( GetOwner() );
|
||||
//Assert( player );
|
||||
|
||||
//NOTENOTE: For now, let this cycle continue when in the air, because it snaps badly without it
|
||||
|
||||
if ( ( !gpGlobals->frametime ) || ( player == NULL ) )
|
||||
{
|
||||
//NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!)
|
||||
return 0.0f;// just use old value
|
||||
}
|
||||
|
||||
//Find the speed of the player
|
||||
float speed = player->GetLocalVelocity().Length2D();
|
||||
|
||||
//FIXME: This maximum speed value must come from the server.
|
||||
// MaxSpeed() is not sufficient for dealing with sprinting - jdw
|
||||
|
||||
speed = clamp( speed, -320, 320 );
|
||||
|
||||
float bob_offset = RemapVal( speed, 0, 320, 0.0f, 1.0f );
|
||||
|
||||
bobtime += ( gpGlobals->curtime - lastbobtime ) * bob_offset;
|
||||
lastbobtime = gpGlobals->curtime;
|
||||
|
||||
//Calculate the vertical bob
|
||||
cycle = bobtime - (int)(bobtime/HL2_BOB_CYCLE_MAX)*HL2_BOB_CYCLE_MAX;
|
||||
cycle /= HL2_BOB_CYCLE_MAX;
|
||||
|
||||
if ( cycle < HL2_BOB_UP )
|
||||
{
|
||||
cycle = M_PI * cycle / HL2_BOB_UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
cycle = M_PI + M_PI*(cycle-HL2_BOB_UP)/(1.0 - HL2_BOB_UP);
|
||||
}
|
||||
|
||||
g_verticalBob = speed*0.005f;
|
||||
g_verticalBob = g_verticalBob*0.3 + g_verticalBob*0.7*sin(cycle);
|
||||
|
||||
g_verticalBob = clamp( g_verticalBob, -7.0f, 4.0f );
|
||||
|
||||
//Calculate the lateral bob
|
||||
cycle = bobtime - (int)(bobtime/HL2_BOB_CYCLE_MAX*2)*HL2_BOB_CYCLE_MAX*2;
|
||||
cycle /= HL2_BOB_CYCLE_MAX*2;
|
||||
|
||||
if ( cycle < HL2_BOB_UP )
|
||||
{
|
||||
cycle = M_PI * cycle / HL2_BOB_UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
cycle = M_PI + M_PI*(cycle-HL2_BOB_UP)/(1.0 - HL2_BOB_UP);
|
||||
}
|
||||
|
||||
g_lateralBob = speed*0.005f;
|
||||
g_lateralBob = g_lateralBob*0.3 + g_lateralBob*0.7*sin(cycle);
|
||||
g_lateralBob = clamp( g_lateralBob, -7.0f, 4.0f );
|
||||
|
||||
//NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!)
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &origin -
|
||||
// &angles -
|
||||
// viewmodelindex -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseHL2MPCombatWeapon::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
|
||||
{
|
||||
Vector forward, right;
|
||||
AngleVectors( angles, &forward, &right, NULL );
|
||||
|
||||
CalcViewmodelBob();
|
||||
|
||||
// Apply bob, but scaled down to 40%
|
||||
VectorMA( origin, g_verticalBob * 0.1f, forward, origin );
|
||||
|
||||
// Z bob a bit more
|
||||
origin[2] += g_verticalBob * 0.1f;
|
||||
|
||||
// bob the angles
|
||||
angles[ ROLL ] += g_verticalBob * 0.5f;
|
||||
angles[ PITCH ] -= g_verticalBob * 0.4f;
|
||||
|
||||
angles[ YAW ] -= g_lateralBob * 0.3f;
|
||||
|
||||
VectorMA( origin, g_lateralBob * 0.8f, right, origin );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
Vector CBaseHL2MPCombatWeapon::GetBulletSpread( WeaponProficiency_t proficiency )
|
||||
{
|
||||
return BaseClass::GetBulletSpread( proficiency );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
float CBaseHL2MPCombatWeapon::GetSpreadBias( WeaponProficiency_t proficiency )
|
||||
{
|
||||
return BaseClass::GetSpreadBias( proficiency );
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const WeaponProficiencyInfo_t *CBaseHL2MPCombatWeapon::GetProficiencyValues()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Server stubs
|
||||
float CBaseHL2MPCombatWeapon::CalcViewmodelBob( void )
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &origin -
|
||||
// &angles -
|
||||
// viewmodelindex -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseHL2MPCombatWeapon::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
Vector CBaseHL2MPCombatWeapon::GetBulletSpread( WeaponProficiency_t proficiency )
|
||||
{
|
||||
Vector baseSpread = BaseClass::GetBulletSpread( proficiency );
|
||||
|
||||
const WeaponProficiencyInfo_t *pProficiencyValues = GetProficiencyValues();
|
||||
float flModifier = (pProficiencyValues)[ proficiency ].spreadscale;
|
||||
return ( baseSpread * flModifier );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
float CBaseHL2MPCombatWeapon::GetSpreadBias( WeaponProficiency_t proficiency )
|
||||
{
|
||||
const WeaponProficiencyInfo_t *pProficiencyValues = GetProficiencyValues();
|
||||
return (pProficiencyValues)[ proficiency ].bias;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const WeaponProficiencyInfo_t *CBaseHL2MPCombatWeapon::GetProficiencyValues()
|
||||
{
|
||||
return GetDefaultProficiencyValues();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const WeaponProficiencyInfo_t *CBaseHL2MPCombatWeapon::GetDefaultProficiencyValues()
|
||||
{
|
||||
// Weapon proficiency table. Keep this in sync with WeaponProficiency_t enum in the header!!
|
||||
static WeaponProficiencyInfo_t g_BaseWeaponProficiencyTable[] =
|
||||
{
|
||||
{ 2.50, 1.0 },
|
||||
{ 2.00, 1.0 },
|
||||
{ 1.50, 1.0 },
|
||||
{ 1.25, 1.0 },
|
||||
{ 1.00, 1.0 },
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT( ARRAYSIZE(g_BaseWeaponProficiencyTable) == WEAPON_PROFICIENCY_PERFECT + 1);
|
||||
|
||||
return g_BaseWeaponProficiencyTable;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
#ifndef WEAPON_BASEHL2MPCOMBATWEAPON_SHARED_H
|
||||
#define WEAPON_BASEHL2MPCOMBATWEAPON_SHARED_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#endif
|
||||
|
||||
#include "weapon_hl2mpbase.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CBaseHL2MPCombatWeapon C_BaseHL2MPCombatWeapon
|
||||
#endif
|
||||
|
||||
class CBaseHL2MPCombatWeapon : public CWeaponHL2MPBase
|
||||
{
|
||||
#if !defined( CLIENT_DLL )
|
||||
DECLARE_DATADESC();
|
||||
#endif
|
||||
|
||||
DECLARE_CLASS( CBaseHL2MPCombatWeapon, CWeaponHL2MPBase );
|
||||
public:
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CBaseHL2MPCombatWeapon();
|
||||
|
||||
virtual bool WeaponShouldBeLowered( void );
|
||||
|
||||
virtual bool Ready( void );
|
||||
virtual bool Lower( void );
|
||||
virtual bool Deploy( void );
|
||||
virtual bool Holster( CBaseCombatWeapon *pSwitchingTo );
|
||||
virtual void WeaponIdle( void );
|
||||
|
||||
virtual void AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles );
|
||||
virtual float CalcViewmodelBob( void );
|
||||
|
||||
virtual Vector GetBulletSpread( WeaponProficiency_t proficiency );
|
||||
virtual float GetSpreadBias( WeaponProficiency_t proficiency );
|
||||
|
||||
virtual const WeaponProficiencyInfo_t *GetProficiencyValues();
|
||||
static const WeaponProficiencyInfo_t *GetDefaultProficiencyValues();
|
||||
|
||||
virtual void ItemHolsterFrame( void );
|
||||
|
||||
protected:
|
||||
|
||||
bool m_bLowered; // Whether the viewmodel is raised or lowered
|
||||
float m_flRaiseTime; // If lowered, the time we should raise the viewmodel
|
||||
float m_flHolsterTime; // When the weapon was holstered
|
||||
|
||||
private:
|
||||
|
||||
CBaseHL2MPCombatWeapon( const CBaseHL2MPCombatWeapon & );
|
||||
};
|
||||
|
||||
#endif // WEAPON_BASEHL2MPCOMBATWEAPON_SHARED_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef WEAPON_PHYSCANNON_H
|
||||
#define WEAPON_PHYSCANNON_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Do we have the super-phys gun?
|
||||
//-----------------------------------------------------------------------------
|
||||
bool PlayerHasMegaPhysCannon();
|
||||
|
||||
// force the physcannon to drop an object (if carried)
|
||||
void PhysCannonForceDrop( CBaseCombatWeapon *pActiveWeapon, CBaseEntity *pOnlyIfHoldingThis );
|
||||
void PhysCannonBeginUpgrade( CBaseAnimating *pAnim );
|
||||
|
||||
bool PlayerPickupControllerIsHoldingEntity( CBaseEntity *pPickupController, CBaseEntity *pHeldEntity );
|
||||
float PlayerPickupGetHeldObjectMass( CBaseEntity *pPickupControllerEntity, IPhysicsObject *pHeldObject );
|
||||
float PhysCannonGetHeldObjectMass( CBaseCombatWeapon *pActiveWeapon, IPhysicsObject *pHeldObject );
|
||||
|
||||
CBaseEntity *PhysCannonGetHeldEntity( CBaseCombatWeapon *pActiveWeapon );
|
||||
|
||||
#endif // WEAPON_PHYSCANNON_H
|
||||
@@ -0,0 +1,339 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "npcevent.h"
|
||||
#include "in_buttons.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#endif
|
||||
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
|
||||
#define PISTOL_FASTEST_REFIRE_TIME 0.1f
|
||||
#define PISTOL_FASTEST_DRY_REFIRE_TIME 0.2f
|
||||
|
||||
#define PISTOL_ACCURACY_SHOT_PENALTY_TIME 0.2f // Applied amount of time each shot adds to the time we must recover from
|
||||
#define PISTOL_ACCURACY_MAXIMUM_PENALTY_TIME 1.5f // Maximum penalty to deal out
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CWeaponPistol C_WeaponPistol
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CWeaponPistol
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class CWeaponPistol : public CBaseHL2MPCombatWeapon
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponPistol, CBaseHL2MPCombatWeapon );
|
||||
|
||||
CWeaponPistol(void);
|
||||
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
void Precache( void );
|
||||
void ItemPostFrame( void );
|
||||
void ItemPreFrame( void );
|
||||
void ItemBusyFrame( void );
|
||||
void PrimaryAttack( void );
|
||||
void AddViewKick( void );
|
||||
void DryFire( void );
|
||||
|
||||
void UpdatePenaltyTime( void );
|
||||
|
||||
Activity GetPrimaryAttackActivity( void );
|
||||
|
||||
virtual bool Reload( void );
|
||||
|
||||
virtual const Vector& GetBulletSpread( void )
|
||||
{
|
||||
static Vector cone;
|
||||
|
||||
float ramp = RemapValClamped( m_flAccuracyPenalty,
|
||||
0.0f,
|
||||
PISTOL_ACCURACY_MAXIMUM_PENALTY_TIME,
|
||||
0.0f,
|
||||
1.0f );
|
||||
|
||||
// We lerp from very accurate to inaccurate over time
|
||||
VectorLerp( VECTOR_CONE_1DEGREES, VECTOR_CONE_6DEGREES, ramp, cone );
|
||||
|
||||
return cone;
|
||||
}
|
||||
|
||||
virtual int GetMinBurst()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual int GetMaxBurst()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
virtual float GetFireRate( void )
|
||||
{
|
||||
return 0.5f;
|
||||
}
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_ACTTABLE();
|
||||
#endif
|
||||
|
||||
private:
|
||||
CNetworkVar( float, m_flSoonestPrimaryAttack );
|
||||
CNetworkVar( float, m_flLastAttackTime );
|
||||
CNetworkVar( float, m_flAccuracyPenalty );
|
||||
CNetworkVar( int, m_nNumShotsFired );
|
||||
|
||||
private:
|
||||
CWeaponPistol( const CWeaponPistol & );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponPistol, DT_WeaponPistol )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponPistol, DT_WeaponPistol )
|
||||
#ifdef CLIENT_DLL
|
||||
RecvPropTime( RECVINFO( m_flSoonestPrimaryAttack ) ),
|
||||
RecvPropTime( RECVINFO( m_flLastAttackTime ) ),
|
||||
RecvPropFloat( RECVINFO( m_flAccuracyPenalty ) ),
|
||||
RecvPropInt( RECVINFO( m_nNumShotsFired ) ),
|
||||
#else
|
||||
SendPropTime( SENDINFO( m_flSoonestPrimaryAttack ) ),
|
||||
SendPropTime( SENDINFO( m_flLastAttackTime ) ),
|
||||
SendPropFloat( SENDINFO( m_flAccuracyPenalty ) ),
|
||||
SendPropInt( SENDINFO( m_nNumShotsFired ) ),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
BEGIN_PREDICTION_DATA( CWeaponPistol )
|
||||
DEFINE_PRED_FIELD( m_flSoonestPrimaryAttack, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_flLastAttackTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_flAccuracyPenalty, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_nNumShotsFired, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_pistol, CWeaponPistol );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_pistol );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
acttable_t CWeaponPistol::m_acttable[] =
|
||||
{
|
||||
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_PISTOL, false },
|
||||
{ ACT_HL2MP_RUN, ACT_HL2MP_RUN_PISTOL, false },
|
||||
{ ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_PISTOL, false },
|
||||
{ ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_PISTOL, false },
|
||||
{ ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL, false },
|
||||
{ ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PISTOL, false },
|
||||
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PISTOL, false },
|
||||
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_PISTOL, false },
|
||||
};
|
||||
|
||||
|
||||
IMPLEMENT_ACTTABLE( CWeaponPistol );
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CWeaponPistol::CWeaponPistol( void )
|
||||
{
|
||||
m_flSoonestPrimaryAttack = gpGlobals->curtime;
|
||||
m_flAccuracyPenalty = 0.0f;
|
||||
|
||||
m_fMinRange1 = 24;
|
||||
m_fMaxRange1 = 1500;
|
||||
m_fMinRange2 = 24;
|
||||
m_fMaxRange2 = 200;
|
||||
|
||||
m_bFiresUnderwater = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponPistol::Precache( void )
|
||||
{
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponPistol::DryFire( void )
|
||||
{
|
||||
WeaponSound( EMPTY );
|
||||
SendWeaponAnim( ACT_VM_DRYFIRE );
|
||||
|
||||
m_flSoonestPrimaryAttack = gpGlobals->curtime + PISTOL_FASTEST_DRY_REFIRE_TIME;
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponPistol::PrimaryAttack( void )
|
||||
{
|
||||
if ( ( gpGlobals->curtime - m_flLastAttackTime ) > 0.5f )
|
||||
{
|
||||
m_nNumShotsFired = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nNumShotsFired++;
|
||||
}
|
||||
|
||||
m_flLastAttackTime = gpGlobals->curtime;
|
||||
m_flSoonestPrimaryAttack = gpGlobals->curtime + PISTOL_FASTEST_REFIRE_TIME;
|
||||
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
|
||||
if( pOwner )
|
||||
{
|
||||
// Each time the player fires the pistol, reset the view punch. This prevents
|
||||
// the aim from 'drifting off' when the player fires very quickly. This may
|
||||
// not be the ideal way to achieve this, but it's cheap and it works, which is
|
||||
// great for a feature we're evaluating. (sjb)
|
||||
pOwner->ViewPunchReset();
|
||||
}
|
||||
|
||||
BaseClass::PrimaryAttack();
|
||||
|
||||
// Add an accuracy penalty which can move past our maximum penalty time if we're really spastic
|
||||
m_flAccuracyPenalty += PISTOL_ACCURACY_SHOT_PENALTY_TIME;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponPistol::UpdatePenaltyTime( void )
|
||||
{
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pOwner == NULL )
|
||||
return;
|
||||
|
||||
// Check our penalty time decay
|
||||
if ( ( ( pOwner->m_nButtons & IN_ATTACK ) == false ) && ( m_flSoonestPrimaryAttack < gpGlobals->curtime ) )
|
||||
{
|
||||
m_flAccuracyPenalty -= gpGlobals->frametime;
|
||||
m_flAccuracyPenalty = clamp( m_flAccuracyPenalty, 0.0f, PISTOL_ACCURACY_MAXIMUM_PENALTY_TIME );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponPistol::ItemPreFrame( void )
|
||||
{
|
||||
UpdatePenaltyTime();
|
||||
|
||||
BaseClass::ItemPreFrame();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponPistol::ItemBusyFrame( void )
|
||||
{
|
||||
UpdatePenaltyTime();
|
||||
|
||||
BaseClass::ItemBusyFrame();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Allows firing as fast as button is pressed
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponPistol::ItemPostFrame( void )
|
||||
{
|
||||
BaseClass::ItemPostFrame();
|
||||
|
||||
if ( m_bInReload )
|
||||
return;
|
||||
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pOwner == NULL )
|
||||
return;
|
||||
|
||||
if ( pOwner->m_nButtons & IN_ATTACK2 )
|
||||
{
|
||||
m_flLastAttackTime = gpGlobals->curtime + PISTOL_FASTEST_REFIRE_TIME;
|
||||
m_flSoonestPrimaryAttack = gpGlobals->curtime + PISTOL_FASTEST_REFIRE_TIME;
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + PISTOL_FASTEST_REFIRE_TIME;
|
||||
}
|
||||
|
||||
//Allow a refire as fast as the player can click
|
||||
if ( ( ( pOwner->m_nButtons & IN_ATTACK ) == false ) && ( m_flSoonestPrimaryAttack < gpGlobals->curtime ) )
|
||||
{
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime - 0.1f;
|
||||
}
|
||||
else if ( ( pOwner->m_nButtons & IN_ATTACK ) && ( m_flNextPrimaryAttack < gpGlobals->curtime ) && ( m_iClip1 <= 0 ) )
|
||||
{
|
||||
DryFire();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
Activity CWeaponPistol::GetPrimaryAttackActivity( void )
|
||||
{
|
||||
if ( m_nNumShotsFired < 1 )
|
||||
return ACT_VM_PRIMARYATTACK;
|
||||
|
||||
if ( m_nNumShotsFired < 2 )
|
||||
return ACT_VM_RECOIL1;
|
||||
|
||||
if ( m_nNumShotsFired < 3 )
|
||||
return ACT_VM_RECOIL2;
|
||||
|
||||
return ACT_VM_RECOIL3;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponPistol::Reload( void )
|
||||
{
|
||||
bool fRet = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
|
||||
if ( fRet )
|
||||
{
|
||||
WeaponSound( RELOAD );
|
||||
m_flAccuracyPenalty = 0.0f;
|
||||
}
|
||||
return fRet;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponPistol::AddViewKick( void )
|
||||
{
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pPlayer == NULL )
|
||||
return;
|
||||
|
||||
QAngle viewPunch;
|
||||
|
||||
viewPunch.x = SharedRandomFloat( "pistolpax", 0.25f, 0.5f );
|
||||
viewPunch.y = SharedRandomFloat( "pistolpay", -.6f, .6f );
|
||||
viewPunch.z = 0.0f;
|
||||
|
||||
//Add it to the view punch
|
||||
pPlayer->ViewPunch( viewPunch );
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,267 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef WEAPON_RPG_H
|
||||
#define WEAPON_RPG_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#include "iviewrender_beams.h"
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
#include "Sprite.h"
|
||||
#include "npcevent.h"
|
||||
#include "beam_shared.h"
|
||||
|
||||
class CWeaponRPG;
|
||||
class CLaserDot;
|
||||
class RocketTrail;
|
||||
|
||||
//###########################################################################
|
||||
// >> CMissile (missile launcher class is below this one!)
|
||||
//###########################################################################
|
||||
class CMissile : public CBaseCombatCharacter
|
||||
{
|
||||
DECLARE_CLASS( CMissile, CBaseCombatCharacter );
|
||||
|
||||
public:
|
||||
CMissile();
|
||||
~CMissile();
|
||||
|
||||
#ifdef HL1_DLL
|
||||
Class_T Classify( void ) { return CLASS_NONE; }
|
||||
#else
|
||||
Class_T Classify( void ) { return CLASS_MISSILE; }
|
||||
#endif
|
||||
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
void MissileTouch( CBaseEntity *pOther );
|
||||
void Explode( void );
|
||||
void ShotDown( void );
|
||||
void AccelerateThink( void );
|
||||
void AugerThink( void );
|
||||
void IgniteThink( void );
|
||||
void SeekThink( void );
|
||||
void DumbFire( void );
|
||||
void SetGracePeriod( float flGracePeriod );
|
||||
|
||||
int OnTakeDamage_Alive( const CTakeDamageInfo &info );
|
||||
void Event_Killed( const CTakeDamageInfo &info );
|
||||
|
||||
virtual float GetDamage() { return m_flDamage; }
|
||||
virtual void SetDamage(float flDamage) { m_flDamage = flDamage; }
|
||||
|
||||
unsigned int PhysicsSolidMaskForEntity( void ) const;
|
||||
|
||||
CHandle<CWeaponRPG> m_hOwner;
|
||||
|
||||
static CMissile *Create( const Vector &vecOrigin, const QAngle &vecAngles, edict_t *pentOwner );
|
||||
|
||||
protected:
|
||||
virtual void DoExplosion();
|
||||
virtual void ComputeActualDotPosition( CLaserDot *pLaserDot, Vector *pActualDotPosition, float *pHomingSpeed );
|
||||
virtual int AugerHealth() { return m_iMaxHealth - 20; }
|
||||
|
||||
// Creates the smoke trail
|
||||
void CreateSmokeTrail( void );
|
||||
|
||||
// Gets the shooting position
|
||||
void GetShootPosition( CLaserDot *pLaserDot, Vector *pShootPosition );
|
||||
|
||||
CHandle<RocketTrail> m_hRocketTrail;
|
||||
float m_flAugerTime; // Amount of time to auger before blowing up anyway
|
||||
float m_flMarkDeadTime;
|
||||
float m_flDamage;
|
||||
|
||||
private:
|
||||
float m_flGracePeriodEndsAt;
|
||||
|
||||
DECLARE_DATADESC();
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Laser dot control
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseEntity *CreateLaserDot( const Vector &origin, CBaseEntity *pOwner, bool bVisibleDot );
|
||||
void SetLaserDotTarget( CBaseEntity *pLaserDot, CBaseEntity *pTarget );
|
||||
void EnableLaserDot( CBaseEntity *pLaserDot, bool bEnable );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Specialized mizzizzile
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAPCMissile : public CMissile
|
||||
{
|
||||
DECLARE_CLASS( CMissile, CMissile );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
public:
|
||||
static CAPCMissile *Create( const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, CBaseEntity *pOwner );
|
||||
|
||||
CAPCMissile();
|
||||
~CAPCMissile();
|
||||
void IgniteDelay( void );
|
||||
void AugerDelay( float flDelayTime );
|
||||
void ExplodeDelay( float flDelayTime );
|
||||
void DisableGuiding();
|
||||
#if defined( HL2_DLL )
|
||||
virtual Class_T Classify ( void ) { return CLASS_COMBINE; }
|
||||
#endif
|
||||
|
||||
void AimAtSpecificTarget( CBaseEntity *pTarget );
|
||||
void SetGuidanceHint( const char *pHintName );
|
||||
|
||||
CAPCMissile *m_pNext;
|
||||
|
||||
protected:
|
||||
virtual void DoExplosion();
|
||||
virtual void ComputeActualDotPosition( CLaserDot *pLaserDot, Vector *pActualDotPosition, float *pHomingSpeed );
|
||||
virtual int AugerHealth();
|
||||
|
||||
private:
|
||||
void Init();
|
||||
void ComputeLeadingPosition( const Vector &vecShootPosition, CBaseEntity *pTarget, Vector *pLeadPosition );
|
||||
void BeginSeekThink();
|
||||
void AugerStartThink();
|
||||
void ExplodeThink();
|
||||
void APCMissileTouch( CBaseEntity *pOther );
|
||||
|
||||
float m_flReachedTargetTime;
|
||||
float m_flIgnitionTime;
|
||||
bool m_bGuidingDisabled;
|
||||
float m_flLastHomingSpeed;
|
||||
EHANDLE m_hSpecificTarget;
|
||||
string_t m_strHint;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finds apc missiles in cone
|
||||
//-----------------------------------------------------------------------------
|
||||
CAPCMissile *FindAPCMissileInCone( const Vector &vecOrigin, const Vector &vecDirection, float flAngle );
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RPG
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CWeaponRPG C_WeaponRPG
|
||||
#endif
|
||||
|
||||
class CWeaponRPG : public CBaseHL2MPCombatWeapon
|
||||
{
|
||||
DECLARE_CLASS( CWeaponRPG, CBaseHL2MPCombatWeapon );
|
||||
public:
|
||||
|
||||
CWeaponRPG();
|
||||
~CWeaponRPG();
|
||||
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
void Precache( void );
|
||||
|
||||
void PrimaryAttack( void );
|
||||
virtual float GetFireRate( void ) { return 1; };
|
||||
void ItemPostFrame( void );
|
||||
|
||||
void Activate( void );
|
||||
void DecrementAmmo( CBaseCombatCharacter *pOwner );
|
||||
|
||||
bool Deploy( void );
|
||||
bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
|
||||
bool Reload( void );
|
||||
bool WeaponShouldBeLowered( void );
|
||||
bool Lower( void );
|
||||
|
||||
bool CanHolster( void );
|
||||
|
||||
virtual void Drop( const Vector &vecVelocity );
|
||||
|
||||
int GetMinBurst() { return 1; }
|
||||
int GetMaxBurst() { return 1; }
|
||||
float GetMinRestTime() { return 4.0; }
|
||||
float GetMaxRestTime() { return 4.0; }
|
||||
|
||||
void StartGuiding( void );
|
||||
void StopGuiding( void );
|
||||
void ToggleGuiding( void );
|
||||
bool IsGuiding( void );
|
||||
|
||||
void NotifyRocketDied( void );
|
||||
|
||||
bool HasAnyAmmo( void );
|
||||
|
||||
void SuppressGuiding( bool state = true );
|
||||
|
||||
void CreateLaserPointer( void );
|
||||
void UpdateLaserPosition( Vector vecMuzzlePos = vec3_origin, Vector vecEndPos = vec3_origin );
|
||||
Vector GetLaserPosition( void );
|
||||
|
||||
// NPC RPG users cheat and directly set the laser pointer's origin
|
||||
void UpdateNPCLaserPosition( const Vector &vecTarget );
|
||||
void SetNPCLaserPosition( const Vector &vecTarget );
|
||||
const Vector &GetNPCLaserPosition( void );
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
// We need to render opaque and translucent pieces
|
||||
virtual RenderGroup_t GetRenderGroup( void ) { return RENDER_GROUP_TWOPASS; }
|
||||
|
||||
virtual void NotifyShouldTransmit( ShouldTransmitState_t state );
|
||||
virtual int DrawModel( int flags );
|
||||
virtual void ViewModelDrawn( C_BaseViewModel *pBaseViewModel );
|
||||
virtual bool IsTranslucent( void );
|
||||
|
||||
void InitBeam( void );
|
||||
void GetWeaponAttachment( int attachmentId, Vector &outVector, Vector *dir = NULL );
|
||||
void DrawEffects( void );
|
||||
// void DrawLaserDot( void );
|
||||
|
||||
CMaterialReference m_hSpriteMaterial; // Used for the laser glint
|
||||
CMaterialReference m_hBeamMaterial; // Used for the laser beam
|
||||
Beam_t *m_pBeam; // Laser beam temp entity
|
||||
|
||||
#endif //CLIENT_DLL
|
||||
|
||||
CBaseEntity *GetMissile( void ) { return m_hMissile; }
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_ACTTABLE();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
CNetworkVar( bool, m_bInitialStateUpdate );
|
||||
CNetworkVar( bool, m_bGuiding );
|
||||
CNetworkVar( bool, m_bHideGuiding );
|
||||
|
||||
CNetworkHandle( CBaseEntity, m_hMissile );
|
||||
CNetworkVar( Vector, m_vecLaserDot );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
CHandle<CLaserDot> m_hLaserDot;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
CWeaponRPG( const CWeaponRPG & );
|
||||
};
|
||||
|
||||
#endif // WEAPON_RPG_H
|
||||
@@ -0,0 +1,634 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "npcevent.h"
|
||||
#include "in_buttons.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#endif
|
||||
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CWeaponShotgun C_WeaponShotgun
|
||||
#endif
|
||||
|
||||
extern ConVar sk_auto_reload_time;
|
||||
extern ConVar sk_plr_num_shotgun_pellets;
|
||||
|
||||
class CWeaponShotgun : public CBaseHL2MPCombatWeapon
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponShotgun, CBaseHL2MPCombatWeapon );
|
||||
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
private:
|
||||
CNetworkVar( bool, m_bNeedPump ); // When emptied completely
|
||||
CNetworkVar( bool, m_bDelayedFire1 ); // Fire primary when finished reloading
|
||||
CNetworkVar( bool, m_bDelayedFire2 ); // Fire secondary when finished reloading
|
||||
CNetworkVar( bool, m_bDelayedReload ); // Reload when finished pump
|
||||
|
||||
public:
|
||||
virtual const Vector& GetBulletSpread( void )
|
||||
{
|
||||
static Vector cone = VECTOR_CONE_10DEGREES;
|
||||
return cone;
|
||||
}
|
||||
|
||||
virtual int GetMinBurst() { return 1; }
|
||||
virtual int GetMaxBurst() { return 3; }
|
||||
|
||||
bool StartReload( void );
|
||||
bool Reload( void );
|
||||
void FillClip( void );
|
||||
void FinishReload( void );
|
||||
void CheckHolsterReload( void );
|
||||
void Pump( void );
|
||||
// void WeaponIdle( void );
|
||||
void ItemHolsterFrame( void );
|
||||
void ItemPostFrame( void );
|
||||
void PrimaryAttack( void );
|
||||
void SecondaryAttack( void );
|
||||
void DryFire( void );
|
||||
virtual float GetFireRate( void ) { return 0.7; };
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_ACTTABLE();
|
||||
#endif
|
||||
|
||||
CWeaponShotgun(void);
|
||||
|
||||
private:
|
||||
CWeaponShotgun( const CWeaponShotgun & );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponShotgun, DT_WeaponShotgun )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponShotgun, DT_WeaponShotgun )
|
||||
#ifdef CLIENT_DLL
|
||||
RecvPropBool( RECVINFO( m_bNeedPump ) ),
|
||||
RecvPropBool( RECVINFO( m_bDelayedFire1 ) ),
|
||||
RecvPropBool( RECVINFO( m_bDelayedFire2 ) ),
|
||||
RecvPropBool( RECVINFO( m_bDelayedReload ) ),
|
||||
#else
|
||||
SendPropBool( SENDINFO( m_bNeedPump ) ),
|
||||
SendPropBool( SENDINFO( m_bDelayedFire1 ) ),
|
||||
SendPropBool( SENDINFO( m_bDelayedFire2 ) ),
|
||||
SendPropBool( SENDINFO( m_bDelayedReload ) ),
|
||||
#endif
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
BEGIN_PREDICTION_DATA( CWeaponShotgun )
|
||||
DEFINE_PRED_FIELD( m_bNeedPump, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_bDelayedFire1, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_bDelayedFire2, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_bDelayedReload, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
END_PREDICTION_DATA()
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_shotgun, CWeaponShotgun );
|
||||
PRECACHE_WEAPON_REGISTER(weapon_shotgun);
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
acttable_t CWeaponShotgun::m_acttable[] =
|
||||
{
|
||||
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_SHOTGUN, false },
|
||||
{ ACT_HL2MP_RUN, ACT_HL2MP_RUN_SHOTGUN, false },
|
||||
{ ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_SHOTGUN, false },
|
||||
{ ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_SHOTGUN, false },
|
||||
{ ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN, false },
|
||||
{ ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_SHOTGUN, false },
|
||||
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_SHOTGUN, false },
|
||||
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SHOTGUN, false },
|
||||
};
|
||||
|
||||
IMPLEMENT_ACTTABLE(CWeaponShotgun);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Override so only reload one shell at a time
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponShotgun::StartReload( void )
|
||||
{
|
||||
if ( m_bNeedPump )
|
||||
return false;
|
||||
|
||||
CBaseCombatCharacter *pOwner = GetOwner();
|
||||
|
||||
if ( pOwner == NULL )
|
||||
return false;
|
||||
|
||||
if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
|
||||
return false;
|
||||
|
||||
if (m_iClip1 >= GetMaxClip1())
|
||||
return false;
|
||||
|
||||
|
||||
int j = MIN(1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
|
||||
|
||||
if (j <= 0)
|
||||
return false;
|
||||
|
||||
SendWeaponAnim( ACT_SHOTGUN_RELOAD_START );
|
||||
|
||||
// Make shotgun shell visible
|
||||
SetBodygroup(1,0);
|
||||
|
||||
pOwner->m_flNextAttack = gpGlobals->curtime;
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
|
||||
m_bInReload = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Override so only reload one shell at a time
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponShotgun::Reload( void )
|
||||
{
|
||||
// Check that StartReload was called first
|
||||
if (!m_bInReload)
|
||||
{
|
||||
Warning("ERROR: Shotgun Reload called incorrectly!\n");
|
||||
}
|
||||
|
||||
CBaseCombatCharacter *pOwner = GetOwner();
|
||||
|
||||
if ( pOwner == NULL )
|
||||
return false;
|
||||
|
||||
if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
|
||||
return false;
|
||||
|
||||
if (m_iClip1 >= GetMaxClip1())
|
||||
return false;
|
||||
|
||||
int j = MIN(1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
|
||||
|
||||
if (j <= 0)
|
||||
return false;
|
||||
|
||||
FillClip();
|
||||
// Play reload on different channel as otherwise steals channel away from fire sound
|
||||
WeaponSound(RELOAD);
|
||||
SendWeaponAnim( ACT_VM_RELOAD );
|
||||
|
||||
pOwner->m_flNextAttack = gpGlobals->curtime;
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Play finish reload anim and fill clip
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponShotgun::FinishReload( void )
|
||||
{
|
||||
// Make shotgun shell invisible
|
||||
SetBodygroup(1,1);
|
||||
|
||||
CBaseCombatCharacter *pOwner = GetOwner();
|
||||
|
||||
if ( pOwner == NULL )
|
||||
return;
|
||||
|
||||
m_bInReload = false;
|
||||
|
||||
// Finish reload animation
|
||||
SendWeaponAnim( ACT_SHOTGUN_RELOAD_FINISH );
|
||||
|
||||
pOwner->m_flNextAttack = gpGlobals->curtime;
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Play finish reload anim and fill clip
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponShotgun::FillClip( void )
|
||||
{
|
||||
CBaseCombatCharacter *pOwner = GetOwner();
|
||||
|
||||
if ( pOwner == NULL )
|
||||
return;
|
||||
|
||||
// Add them to the clip
|
||||
if ( pOwner->GetAmmoCount( m_iPrimaryAmmoType ) > 0 )
|
||||
{
|
||||
if ( Clip1() < GetMaxClip1() )
|
||||
{
|
||||
m_iClip1++;
|
||||
pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Play weapon pump anim
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponShotgun::Pump( void )
|
||||
{
|
||||
CBaseCombatCharacter *pOwner = GetOwner();
|
||||
|
||||
if ( pOwner == NULL )
|
||||
return;
|
||||
|
||||
m_bNeedPump = false;
|
||||
|
||||
if ( m_bDelayedReload )
|
||||
{
|
||||
m_bDelayedReload = false;
|
||||
StartReload();
|
||||
}
|
||||
|
||||
WeaponSound( SPECIAL1 );
|
||||
|
||||
// Finish reload animation
|
||||
SendWeaponAnim( ACT_SHOTGUN_PUMP );
|
||||
|
||||
pOwner->m_flNextAttack = gpGlobals->curtime + SequenceDuration();
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponShotgun::DryFire( void )
|
||||
{
|
||||
WeaponSound(EMPTY);
|
||||
SendWeaponAnim( ACT_VM_DRYFIRE );
|
||||
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponShotgun::PrimaryAttack( void )
|
||||
{
|
||||
// Only the player fires this way so we can cast
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
|
||||
if (!pPlayer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// MUST call sound before removing a round from the clip of a CMachineGun
|
||||
WeaponSound(SINGLE);
|
||||
|
||||
pPlayer->DoMuzzleFlash();
|
||||
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
||||
|
||||
// Don't fire again until fire animation has completed
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
m_iClip1 -= 1;
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
Vector vecSrc = pPlayer->Weapon_ShootPosition( );
|
||||
Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );
|
||||
|
||||
FireBulletsInfo_t info( 7, vecSrc, vecAiming, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType );
|
||||
info.m_pAttacker = pPlayer;
|
||||
|
||||
// Fire the bullets, and force the first shot to be perfectly accuracy
|
||||
pPlayer->FireBullets( info );
|
||||
|
||||
QAngle punch;
|
||||
punch.Init( SharedRandomFloat( "shotgunpax", -2, -1 ), SharedRandomFloat( "shotgunpay", -2, 2 ), 0 );
|
||||
pPlayer->ViewPunch( punch );
|
||||
|
||||
if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
|
||||
{
|
||||
// HEV suit - indicate out of ammo condition
|
||||
pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
|
||||
}
|
||||
|
||||
m_bNeedPump = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponShotgun::SecondaryAttack( void )
|
||||
{
|
||||
// Only the player fires this way so we can cast
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
|
||||
if (!pPlayer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pPlayer->m_nButtons &= ~IN_ATTACK2;
|
||||
// MUST call sound before removing a round from the clip of a CMachineGun
|
||||
WeaponSound(WPN_DOUBLE);
|
||||
|
||||
pPlayer->DoMuzzleFlash();
|
||||
|
||||
SendWeaponAnim( ACT_VM_SECONDARYATTACK );
|
||||
|
||||
// Don't fire again until fire animation has completed
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
|
||||
m_iClip1 -= 2; // Shotgun uses same clip for primary and secondary attacks
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
Vector vecSrc = pPlayer->Weapon_ShootPosition();
|
||||
Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );
|
||||
|
||||
FireBulletsInfo_t info( 12, vecSrc, vecAiming, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType );
|
||||
info.m_pAttacker = pPlayer;
|
||||
|
||||
// Fire the bullets, and force the first shot to be perfectly accuracy
|
||||
pPlayer->FireBullets( info );
|
||||
pPlayer->ViewPunch( QAngle(SharedRandomFloat( "shotgunsax", -5, 5 ),0,0) );
|
||||
|
||||
if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
|
||||
{
|
||||
// HEV suit - indicate out of ammo condition
|
||||
pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
|
||||
}
|
||||
|
||||
m_bNeedPump = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Override so shotgun can do mulitple reloads in a row
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponShotgun::ItemPostFrame( void )
|
||||
{
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
if (!pOwner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_bNeedPump && ( pOwner->m_nButtons & IN_RELOAD ) )
|
||||
{
|
||||
m_bDelayedReload = true;
|
||||
}
|
||||
|
||||
if (m_bInReload)
|
||||
{
|
||||
// If I'm primary firing and have one round stop reloading and fire
|
||||
if ((pOwner->m_nButtons & IN_ATTACK ) && (m_iClip1 >=1) && !m_bNeedPump )
|
||||
{
|
||||
m_bInReload = false;
|
||||
m_bNeedPump = false;
|
||||
m_bDelayedFire1 = true;
|
||||
}
|
||||
// If I'm secondary firing and have two rounds stop reloading and fire
|
||||
else if ((pOwner->m_nButtons & IN_ATTACK2 ) && (m_iClip1 >=2) && !m_bNeedPump )
|
||||
{
|
||||
m_bInReload = false;
|
||||
m_bNeedPump = false;
|
||||
m_bDelayedFire2 = true;
|
||||
}
|
||||
else if (m_flNextPrimaryAttack <= gpGlobals->curtime)
|
||||
{
|
||||
// If out of ammo end reload
|
||||
if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <=0)
|
||||
{
|
||||
FinishReload();
|
||||
return;
|
||||
}
|
||||
// If clip not full reload again
|
||||
if (m_iClip1 < GetMaxClip1())
|
||||
{
|
||||
Reload();
|
||||
return;
|
||||
}
|
||||
// Clip full, stop reloading
|
||||
else
|
||||
{
|
||||
FinishReload();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make shotgun shell invisible
|
||||
SetBodygroup(1,1);
|
||||
}
|
||||
|
||||
if ((m_bNeedPump) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
|
||||
{
|
||||
Pump();
|
||||
return;
|
||||
}
|
||||
|
||||
// Shotgun uses same timing and ammo for secondary attack
|
||||
if ((m_bDelayedFire2 || pOwner->m_nButtons & IN_ATTACK2)&&(m_flNextPrimaryAttack <= gpGlobals->curtime))
|
||||
{
|
||||
m_bDelayedFire2 = false;
|
||||
|
||||
if ( (m_iClip1 <= 1 && UsesClipsForAmmo1()))
|
||||
{
|
||||
// If only one shell is left, do a single shot instead
|
||||
if ( m_iClip1 == 1 )
|
||||
{
|
||||
PrimaryAttack();
|
||||
}
|
||||
else if (!pOwner->GetAmmoCount(m_iPrimaryAmmoType))
|
||||
{
|
||||
DryFire();
|
||||
}
|
||||
else
|
||||
{
|
||||
StartReload();
|
||||
}
|
||||
}
|
||||
|
||||
// Fire underwater?
|
||||
else if (GetOwner()->GetWaterLevel() == 3 && m_bFiresUnderwater == false)
|
||||
{
|
||||
WeaponSound(EMPTY);
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the firing button was just pressed, reset the firing time
|
||||
if ( pOwner->m_afButtonPressed & IN_ATTACK )
|
||||
{
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime;
|
||||
}
|
||||
SecondaryAttack();
|
||||
}
|
||||
}
|
||||
else if ( (m_bDelayedFire1 || pOwner->m_nButtons & IN_ATTACK) && m_flNextPrimaryAttack <= gpGlobals->curtime)
|
||||
{
|
||||
m_bDelayedFire1 = false;
|
||||
if ( (m_iClip1 <= 0 && UsesClipsForAmmo1()) || ( !UsesClipsForAmmo1() && !pOwner->GetAmmoCount(m_iPrimaryAmmoType) ) )
|
||||
{
|
||||
if (!pOwner->GetAmmoCount(m_iPrimaryAmmoType))
|
||||
{
|
||||
DryFire();
|
||||
}
|
||||
else
|
||||
{
|
||||
StartReload();
|
||||
}
|
||||
}
|
||||
// Fire underwater?
|
||||
else if (pOwner->GetWaterLevel() == 3 && m_bFiresUnderwater == false)
|
||||
{
|
||||
WeaponSound(EMPTY);
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the firing button was just pressed, reset the firing time
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
if ( pPlayer && pPlayer->m_afButtonPressed & IN_ATTACK )
|
||||
{
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime;
|
||||
}
|
||||
PrimaryAttack();
|
||||
}
|
||||
}
|
||||
|
||||
if ( pOwner->m_nButtons & IN_RELOAD && UsesClipsForAmmo1() && !m_bInReload )
|
||||
{
|
||||
// reload when reload is pressed, or if no buttons are down and weapon is empty.
|
||||
StartReload();
|
||||
}
|
||||
else
|
||||
{
|
||||
// no fire buttons down
|
||||
m_bFireOnEmpty = false;
|
||||
|
||||
if ( !HasAnyAmmo() && m_flNextPrimaryAttack < gpGlobals->curtime )
|
||||
{
|
||||
// weapon isn't useable, switch.
|
||||
if ( !(GetWeaponFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && pOwner->SwitchToNextBestWeapon( this ) )
|
||||
{
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.3;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
|
||||
if ( m_iClip1 <= 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime )
|
||||
{
|
||||
if (StartReload())
|
||||
{
|
||||
// if we've successfully started to reload, we're done
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WeaponIdle( );
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CWeaponShotgun::CWeaponShotgun( void )
|
||||
{
|
||||
m_bReloadsSingly = true;
|
||||
|
||||
m_bNeedPump = false;
|
||||
m_bDelayedFire1 = false;
|
||||
m_bDelayedFire2 = false;
|
||||
|
||||
m_fMinRange1 = 0.0;
|
||||
m_fMaxRange1 = 500;
|
||||
m_fMinRange2 = 0.0;
|
||||
m_fMaxRange2 = 200;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponShotgun::ItemHolsterFrame( void )
|
||||
{
|
||||
// Must be player held
|
||||
if ( GetOwner() && GetOwner()->IsPlayer() == false )
|
||||
return;
|
||||
|
||||
// We can't be active
|
||||
if ( GetOwner()->GetActiveWeapon() == this )
|
||||
return;
|
||||
|
||||
// If it's been longer than three seconds, reload
|
||||
if ( ( gpGlobals->curtime - m_flHolsterTime ) > sk_auto_reload_time.GetFloat() )
|
||||
{
|
||||
// Reset the timer
|
||||
m_flHolsterTime = gpGlobals->curtime;
|
||||
|
||||
if ( GetOwner() == NULL )
|
||||
return;
|
||||
|
||||
if ( m_iClip1 == GetMaxClip1() )
|
||||
return;
|
||||
|
||||
// Just load the clip with no animations
|
||||
int ammoFill = MIN( (GetMaxClip1() - m_iClip1), GetOwner()->GetAmmoCount( GetPrimaryAmmoType() ) );
|
||||
|
||||
GetOwner()->RemoveAmmo( ammoFill, GetPrimaryAmmoType() );
|
||||
m_iClip1 += ammoFill;
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================
|
||||
// Purpose:
|
||||
//==================================================
|
||||
/*
|
||||
void CWeaponShotgun::WeaponIdle( void )
|
||||
{
|
||||
//Only the player fires this way so we can cast
|
||||
CBasePlayer *pPlayer = GetOwner()
|
||||
|
||||
if ( pPlayer == NULL )
|
||||
return;
|
||||
|
||||
//If we're on a target, play the new anim
|
||||
if ( pPlayer->IsOnTarget() )
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_IDLE_ACTIVE );
|
||||
}
|
||||
}
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,91 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: SLAM
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef WEAPONSLAM_H
|
||||
#define WEAPONSLAM_H
|
||||
|
||||
#include "basegrenade_shared.h"
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
|
||||
enum
|
||||
{
|
||||
SLAM_TRIPMINE_READY,
|
||||
SLAM_SATCHEL_THROW,
|
||||
SLAM_SATCHEL_ATTACH,
|
||||
};
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CWeapon_SLAM C_Weapon_SLAM
|
||||
#endif
|
||||
|
||||
class CWeapon_SLAM : public CBaseHL2MPCombatWeapon
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeapon_SLAM, CBaseHL2MPCombatWeapon );
|
||||
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
CNetworkVar( int, m_tSlamState );
|
||||
CNetworkVar( bool, m_bDetonatorArmed );
|
||||
CNetworkVar( bool, m_bNeedDetonatorDraw);
|
||||
CNetworkVar( bool, m_bNeedDetonatorHolster);
|
||||
CNetworkVar( bool, m_bNeedReload);
|
||||
CNetworkVar( bool, m_bClearReload);
|
||||
CNetworkVar( bool, m_bThrowSatchel);
|
||||
CNetworkVar( bool, m_bAttachSatchel);
|
||||
CNetworkVar( bool, m_bAttachTripmine);
|
||||
float m_flWallSwitchTime;
|
||||
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
|
||||
void PrimaryAttack( void );
|
||||
void SecondaryAttack( void );
|
||||
void WeaponIdle( void );
|
||||
void Weapon_Switch( void );
|
||||
void SLAMThink( void );
|
||||
|
||||
void SetPickupTouch( void );
|
||||
void SlamTouch( CBaseEntity *pOther ); // default weapon touch
|
||||
void ItemPostFrame( void );
|
||||
bool Reload( void );
|
||||
void SetSlamState( int newState );
|
||||
bool CanAttachSLAM(void); // In position where can attach SLAM?
|
||||
bool AnyUndetonatedCharges(void);
|
||||
void StartTripmineAttach( void );
|
||||
void TripmineAttach( void );
|
||||
|
||||
void StartSatchelDetonate( void );
|
||||
void SatchelDetonate( void );
|
||||
void StartSatchelThrow( void );
|
||||
void StartSatchelAttach( void );
|
||||
void SatchelThrow( void );
|
||||
void SatchelAttach( void );
|
||||
bool Deploy( void );
|
||||
bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
|
||||
|
||||
|
||||
CWeapon_SLAM();
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_ACTTABLE();
|
||||
DECLARE_DATADESC();
|
||||
#endif
|
||||
|
||||
private:
|
||||
CWeapon_SLAM( const CWeapon_SLAM & );
|
||||
};
|
||||
|
||||
|
||||
#endif //WEAPONSLAM_H
|
||||
@@ -0,0 +1,264 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "npcevent.h"
|
||||
#include "in_buttons.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#else
|
||||
#include "grenade_ar2.h"
|
||||
#include "hl2mp_player.h"
|
||||
#include "basegrenade_shared.h"
|
||||
#endif
|
||||
|
||||
#include "weapon_hl2mpbase.h"
|
||||
#include "weapon_hl2mpbase_machinegun.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CWeaponSMG1 C_WeaponSMG1
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define SMG1_GRENADE_DAMAGE 100.0f
|
||||
#define SMG1_GRENADE_RADIUS 250.0f
|
||||
|
||||
class CWeaponSMG1 : public CHL2MPMachineGun
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponSMG1, CHL2MPMachineGun );
|
||||
|
||||
CWeaponSMG1();
|
||||
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
|
||||
void Precache( void );
|
||||
void AddViewKick( void );
|
||||
void SecondaryAttack( void );
|
||||
|
||||
int GetMinBurst() { return 2; }
|
||||
int GetMaxBurst() { return 5; }
|
||||
|
||||
virtual void Equip( CBaseCombatCharacter *pOwner );
|
||||
bool Reload( void );
|
||||
|
||||
float GetFireRate( void ) { return 0.075f; } // 13.3hz
|
||||
Activity GetPrimaryAttackActivity( void );
|
||||
|
||||
virtual const Vector& GetBulletSpread( void )
|
||||
{
|
||||
static const Vector cone = VECTOR_CONE_5DEGREES;
|
||||
return cone;
|
||||
}
|
||||
|
||||
const WeaponProficiencyInfo_t *GetProficiencyValues();
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_ACTTABLE();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
Vector m_vecTossVelocity;
|
||||
float m_flNextGrenadeCheck;
|
||||
|
||||
private:
|
||||
CWeaponSMG1( const CWeaponSMG1 & );
|
||||
};
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponSMG1, DT_WeaponSMG1 )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponSMG1, DT_WeaponSMG1 )
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponSMG1 )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_smg1, CWeaponSMG1 );
|
||||
PRECACHE_WEAPON_REGISTER(weapon_smg1);
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
acttable_t CWeaponSMG1::m_acttable[] =
|
||||
{
|
||||
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_SMG1, false },
|
||||
{ ACT_HL2MP_RUN, ACT_HL2MP_RUN_SMG1, false },
|
||||
{ ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_SMG1, false },
|
||||
{ ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_SMG1, false },
|
||||
{ ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1, false },
|
||||
{ ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_SMG1, false },
|
||||
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_SMG1, false },
|
||||
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SMG1, false },
|
||||
};
|
||||
|
||||
IMPLEMENT_ACTTABLE(CWeaponSMG1);
|
||||
#endif
|
||||
|
||||
//=========================================================
|
||||
CWeaponSMG1::CWeaponSMG1( )
|
||||
{
|
||||
m_fMinRange1 = 0;// No minimum range.
|
||||
m_fMaxRange1 = 1400;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponSMG1::Precache( void )
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
UTIL_PrecacheOther("grenade_ar2");
|
||||
#endif
|
||||
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Give this weapon longer range when wielded by an ally NPC.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponSMG1::Equip( CBaseCombatCharacter *pOwner )
|
||||
{
|
||||
m_fMaxRange1 = 1400;
|
||||
|
||||
BaseClass::Equip( pOwner );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Activity
|
||||
//-----------------------------------------------------------------------------
|
||||
Activity CWeaponSMG1::GetPrimaryAttackActivity( void )
|
||||
{
|
||||
if ( m_nShotsFired < 2 )
|
||||
return ACT_VM_PRIMARYATTACK;
|
||||
|
||||
if ( m_nShotsFired < 3 )
|
||||
return ACT_VM_RECOIL1;
|
||||
|
||||
if ( m_nShotsFired < 4 )
|
||||
return ACT_VM_RECOIL2;
|
||||
|
||||
return ACT_VM_RECOIL3;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponSMG1::Reload( void )
|
||||
{
|
||||
bool fRet;
|
||||
float fCacheTime = m_flNextSecondaryAttack;
|
||||
|
||||
fRet = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
|
||||
if ( fRet )
|
||||
{
|
||||
// Undo whatever the reload process has done to our secondary
|
||||
// attack timer. We allow you to interrupt reloading to fire
|
||||
// a grenade.
|
||||
m_flNextSecondaryAttack = GetOwner()->m_flNextAttack = fCacheTime;
|
||||
|
||||
WeaponSound( RELOAD );
|
||||
}
|
||||
|
||||
return fRet;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponSMG1::AddViewKick( void )
|
||||
{
|
||||
#define EASY_DAMPEN 0.5f
|
||||
#define MAX_VERTICAL_KICK 1.0f //Degrees
|
||||
#define SLIDE_LIMIT 2.0f //Seconds
|
||||
|
||||
//Get the view kick
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pPlayer == NULL )
|
||||
return;
|
||||
|
||||
DoMachineGunKick( pPlayer, EASY_DAMPEN, MAX_VERTICAL_KICK, m_fFireDuration, SLIDE_LIMIT );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponSMG1::SecondaryAttack( void )
|
||||
{
|
||||
// Only the player fires this way so we can cast
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
|
||||
if ( pPlayer == NULL )
|
||||
return;
|
||||
|
||||
//Must have ammo
|
||||
if ( ( pPlayer->GetAmmoCount( m_iSecondaryAmmoType ) <= 0 ) || ( pPlayer->GetWaterLevel() == 3 ) )
|
||||
{
|
||||
SendWeaponAnim( ACT_VM_DRYFIRE );
|
||||
BaseClass::WeaponSound( EMPTY );
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f;
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_bInReload )
|
||||
m_bInReload = false;
|
||||
|
||||
// MUST call sound before removing a round from the clip of a CMachineGun
|
||||
BaseClass::WeaponSound( WPN_DOUBLE );
|
||||
|
||||
Vector vecSrc = pPlayer->Weapon_ShootPosition();
|
||||
Vector vecThrow;
|
||||
// Don't autoaim on grenade tosses
|
||||
AngleVectors( pPlayer->EyeAngles() + pPlayer->GetPunchAngle(), &vecThrow );
|
||||
VectorScale( vecThrow, 1000.0f, vecThrow );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
//Create the grenade
|
||||
CGrenadeAR2 *pGrenade = (CGrenadeAR2*)Create( "grenade_ar2", vecSrc, vec3_angle, pPlayer );
|
||||
pGrenade->SetAbsVelocity( vecThrow );
|
||||
|
||||
pGrenade->SetLocalAngularVelocity( RandomAngle( -400, 400 ) );
|
||||
pGrenade->SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
|
||||
pGrenade->SetThrower( GetOwner() );
|
||||
pGrenade->SetDamage( SMG1_GRENADE_DAMAGE );
|
||||
pGrenade->SetDamageRadius( SMG1_GRENADE_RADIUS );
|
||||
#endif
|
||||
|
||||
SendWeaponAnim( ACT_VM_SECONDARYATTACK );
|
||||
|
||||
// player "shoot" animation
|
||||
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
// Decrease ammo
|
||||
pPlayer->RemoveAmmo( 1, m_iSecondaryAmmoType );
|
||||
|
||||
// Can shoot again immediately
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + 0.5f;
|
||||
|
||||
// Can blow up after a short delay (so have time to release mouse button)
|
||||
m_flNextSecondaryAttack = gpGlobals->curtime + 1.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const WeaponProficiencyInfo_t *CWeaponSMG1::GetProficiencyValues()
|
||||
{
|
||||
static WeaponProficiencyInfo_t proficiencyTable[] =
|
||||
{
|
||||
{ 7.0, 0.75 },
|
||||
{ 5.00, 0.75 },
|
||||
{ 10.0/3.0, 0.75 },
|
||||
{ 5.0/3.0, 0.75 },
|
||||
{ 1.00, 1.0 },
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT( ARRAYSIZE(proficiencyTable) == WEAPON_PROFICIENCY_PERFECT + 1);
|
||||
|
||||
return proficiencyTable;
|
||||
}
|
||||
@@ -0,0 +1,902 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Stun Stick- beating stick with a zappy end
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "npcevent.h"
|
||||
#include "weapon_hl2mpbasebasebludgeon.h"
|
||||
#include "IEffects.h"
|
||||
#include "debugoverlay_shared.h"
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
#include "npc_metropolice.h"
|
||||
#include "te_effect_dispatch.h"
|
||||
#endif
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#include "iviewrender_beams.h"
|
||||
#include "beam_shared.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "model_types.h"
|
||||
#include "c_te_effect_dispatch.h"
|
||||
#include "fx_quad.h"
|
||||
#include "fx.h"
|
||||
|
||||
extern void DrawHalo( IMaterial* pMaterial, const Vector &source, float scale, float const *color, float flHDRColorScale );
|
||||
extern void FormatViewModelAttachment( Vector &vOrigin, bool bInverse );
|
||||
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
extern ConVar metropolice_move_and_melee;
|
||||
|
||||
#define STUNSTICK_RANGE 75.0f
|
||||
#define STUNSTICK_REFIRE 0.8f
|
||||
#define STUNSTICK_BEAM_MATERIAL "sprites/lgtning.vmt"
|
||||
#define STUNSTICK_GLOW_MATERIAL "sprites/light_glow02_add"
|
||||
#define STUNSTICK_GLOW_MATERIAL2 "effects/blueflare1"
|
||||
#define STUNSTICK_GLOW_MATERIAL_NOZ "sprites/light_glow02_add_noz"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CWeaponStunStick C_WeaponStunStick
|
||||
#endif
|
||||
|
||||
class CWeaponStunStick : public CBaseHL2MPBludgeonWeapon
|
||||
{
|
||||
DECLARE_CLASS( CWeaponStunStick, CBaseHL2MPBludgeonWeapon );
|
||||
|
||||
public:
|
||||
|
||||
CWeaponStunStick();
|
||||
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
DECLARE_ACTTABLE();
|
||||
#endif
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
virtual int DrawModel( int flags );
|
||||
virtual void ClientThink( void );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual RenderGroup_t GetRenderGroup( void );
|
||||
virtual void ViewModelDrawn( C_BaseViewModel *pBaseViewModel );
|
||||
|
||||
#endif
|
||||
|
||||
virtual void Precache();
|
||||
|
||||
void Spawn();
|
||||
|
||||
float GetRange( void ) { return STUNSTICK_RANGE; }
|
||||
float GetFireRate( void ) { return STUNSTICK_REFIRE; }
|
||||
|
||||
|
||||
bool Deploy( void );
|
||||
bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
|
||||
|
||||
void Drop( const Vector &vecVelocity );
|
||||
void ImpactEffect( trace_t &traceHit );
|
||||
void SecondaryAttack( void ) {}
|
||||
void SetStunState( bool state );
|
||||
bool GetStunState( void );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
|
||||
int WeaponMeleeAttack1Condition( float flDot, float flDist );
|
||||
#endif
|
||||
|
||||
float GetDamageForActivity( Activity hitActivity );
|
||||
|
||||
CWeaponStunStick( const CWeaponStunStick & );
|
||||
|
||||
private:
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
#define NUM_BEAM_ATTACHMENTS 9
|
||||
|
||||
struct stunstickBeamInfo_t
|
||||
{
|
||||
int IDs[2]; // 0 - top, 1 - bottom
|
||||
};
|
||||
|
||||
stunstickBeamInfo_t m_BeamAttachments[NUM_BEAM_ATTACHMENTS]; // Lookup for arc attachment points on the head of the stick
|
||||
int m_BeamCenterAttachment; // "Core" of the effect (center of the head)
|
||||
|
||||
void SetupAttachmentPoints( void );
|
||||
void DrawFirstPersonEffects( void );
|
||||
void DrawThirdPersonEffects( void );
|
||||
void DrawEffects( void );
|
||||
bool InSwing( void );
|
||||
|
||||
bool m_bSwungLastFrame;
|
||||
|
||||
#define FADE_DURATION 0.25f
|
||||
|
||||
float m_flFadeTime;
|
||||
|
||||
#endif
|
||||
|
||||
CNetworkVar( bool, m_bActive );
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CWeaponStunStick
|
||||
//-----------------------------------------------------------------------------
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponStunStick, DT_WeaponStunStick )
|
||||
|
||||
BEGIN_NETWORK_TABLE( CWeaponStunStick, DT_WeaponStunStick )
|
||||
#ifdef CLIENT_DLL
|
||||
RecvPropInt( RECVINFO( m_bActive ) ),
|
||||
#else
|
||||
SendPropInt( SENDINFO( m_bActive ), 1, SPROP_UNSIGNED ),
|
||||
#endif
|
||||
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( CWeaponStunStick )
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( weapon_stunstick, CWeaponStunStick );
|
||||
PRECACHE_WEAPON_REGISTER( weapon_stunstick );
|
||||
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
acttable_t CWeaponStunStick::m_acttable[] =
|
||||
{
|
||||
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true },
|
||||
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_MELEE, false },
|
||||
{ ACT_HL2MP_RUN, ACT_HL2MP_RUN_MELEE, false },
|
||||
{ ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_MELEE, false },
|
||||
{ ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_MELEE, false },
|
||||
{ ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE, false },
|
||||
{ ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_MELEE, false },
|
||||
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_MELEE, false },
|
||||
};
|
||||
|
||||
IMPLEMENT_ACTTABLE(CWeaponStunStick);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CWeaponStunStick::CWeaponStunStick( void )
|
||||
{
|
||||
// HACK: Don't call SetStunState because this tried to Emit a sound before
|
||||
// any players are connected which is a bug
|
||||
m_bActive = false;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
m_bSwungLastFrame = false;
|
||||
m_flFadeTime = FADE_DURATION; // Start off past the fade point
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponStunStick::Spawn()
|
||||
{
|
||||
Precache();
|
||||
|
||||
BaseClass::Spawn();
|
||||
AddSolidFlags( FSOLID_NOT_STANDABLE );
|
||||
}
|
||||
|
||||
void CWeaponStunStick::Precache()
|
||||
{
|
||||
BaseClass::Precache();
|
||||
|
||||
PrecacheScriptSound( "Weapon_StunStick.Activate" );
|
||||
PrecacheScriptSound( "Weapon_StunStick.Deactivate" );
|
||||
|
||||
PrecacheModel( STUNSTICK_BEAM_MATERIAL );
|
||||
PrecacheModel( "sprites/light_glow02_add.vmt" );
|
||||
PrecacheModel( "effects/blueflare1.vmt" );
|
||||
PrecacheModel( "sprites/light_glow02_add_noz.vmt" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get the damage amount for the animation we're doing
|
||||
// Input : hitActivity - currently played activity
|
||||
// Output : Damage amount
|
||||
//-----------------------------------------------------------------------------
|
||||
float CWeaponStunStick::GetDamageForActivity( Activity hitActivity )
|
||||
{
|
||||
return 40.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Attempt to lead the target (needed because citizens can't hit manhacks with the crowbar!)
|
||||
//-----------------------------------------------------------------------------
|
||||
extern ConVar sk_crowbar_lead_time;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponStunStick::ImpactEffect( trace_t &traceHit )
|
||||
{
|
||||
|
||||
//#ifndef CLIENT_DLL
|
||||
|
||||
CEffectData data;
|
||||
|
||||
data.m_vNormal = traceHit.plane.normal;
|
||||
data.m_vOrigin = traceHit.endpos + ( data.m_vNormal * 4.0f );
|
||||
|
||||
DispatchEffect( "StunstickImpact", data );
|
||||
|
||||
//#endif
|
||||
|
||||
//FIXME: need new decals
|
||||
UTIL_ImpactTrace( &traceHit, DMG_CLUB );
|
||||
}
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
|
||||
int CWeaponStunStick::WeaponMeleeAttack1Condition( float flDot, float flDist )
|
||||
{
|
||||
// Attempt to lead the target (needed because citizens can't hit manhacks with the crowbar!)
|
||||
CAI_BaseNPC *pNPC = GetOwner()->MyNPCPointer();
|
||||
CBaseEntity *pEnemy = pNPC->GetEnemy();
|
||||
if (!pEnemy)
|
||||
return COND_NONE;
|
||||
|
||||
Vector vecVelocity;
|
||||
AngularImpulse angVelocity;
|
||||
pEnemy->GetVelocity( &vecVelocity, &angVelocity );
|
||||
|
||||
// Project where the enemy will be in a little while, add some randomness so he doesn't always hit
|
||||
float dt = sk_crowbar_lead_time.GetFloat();
|
||||
dt += random->RandomFloat( -0.3f, 0.2f );
|
||||
if ( dt < 0.0f )
|
||||
dt = 0.0f;
|
||||
|
||||
Vector vecExtrapolatedPos;
|
||||
VectorMA( pEnemy->WorldSpaceCenter(), dt, vecVelocity, vecExtrapolatedPos );
|
||||
|
||||
Vector vecDelta;
|
||||
VectorSubtract( vecExtrapolatedPos, pNPC->WorldSpaceCenter(), vecDelta );
|
||||
|
||||
if ( fabs( vecDelta.z ) > 70 )
|
||||
{
|
||||
return COND_TOO_FAR_TO_ATTACK;
|
||||
}
|
||||
|
||||
Vector vecForward = pNPC->BodyDirection2D( );
|
||||
vecDelta.z = 0.0f;
|
||||
float flExtrapolatedDot = DotProduct2D( vecDelta.AsVector2D(), vecForward.AsVector2D() );
|
||||
if ((flDot < 0.7) && (flExtrapolatedDot < 0.7))
|
||||
{
|
||||
return COND_NOT_FACING_ATTACK;
|
||||
}
|
||||
|
||||
float flExtrapolatedDist = Vector2DNormalize( vecDelta.AsVector2D() );
|
||||
|
||||
if( pEnemy->IsPlayer() )
|
||||
{
|
||||
//Vector vecDir = pEnemy->GetSmoothedVelocity();
|
||||
//float flSpeed = VectorNormalize( vecDir );
|
||||
|
||||
// If player will be in front of me in one-half second, clock his arse.
|
||||
Vector vecProjectEnemy = pEnemy->GetAbsOrigin() + (pEnemy->GetAbsVelocity() * 0.35);
|
||||
Vector vecProjectMe = GetAbsOrigin();
|
||||
|
||||
if( (vecProjectMe - vecProjectEnemy).Length2D() <= 48.0f )
|
||||
{
|
||||
return COND_CAN_MELEE_ATTACK1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if( metropolice_move_and_melee.GetBool() )
|
||||
{
|
||||
if( pNPC->IsMoving() )
|
||||
{
|
||||
flTargetDist *= 1.5f;
|
||||
}
|
||||
}
|
||||
*/
|
||||
float flTargetDist = 48.0f;
|
||||
if ((flDist > flTargetDist) && (flExtrapolatedDist > flTargetDist))
|
||||
{
|
||||
return COND_TOO_FAR_TO_ATTACK;
|
||||
}
|
||||
|
||||
return COND_CAN_MELEE_ATTACK1;
|
||||
}
|
||||
|
||||
|
||||
void CWeaponStunStick::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
|
||||
{
|
||||
switch( pEvent->event )
|
||||
{
|
||||
case EVENT_WEAPON_MELEE_HIT:
|
||||
{
|
||||
// Trace up or down based on where the enemy is...
|
||||
// But only if we're basically facing that direction
|
||||
Vector vecDirection;
|
||||
AngleVectors( GetAbsAngles(), &vecDirection );
|
||||
|
||||
CBaseEntity *pEnemy = pOperator->MyNPCPointer() ? pOperator->MyNPCPointer()->GetEnemy() : NULL;
|
||||
if ( pEnemy )
|
||||
{
|
||||
Vector vecDelta;
|
||||
VectorSubtract( pEnemy->WorldSpaceCenter(), pOperator->Weapon_ShootPosition(), vecDelta );
|
||||
VectorNormalize( vecDelta );
|
||||
|
||||
Vector2D vecDelta2D = vecDelta.AsVector2D();
|
||||
Vector2DNormalize( vecDelta2D );
|
||||
if ( DotProduct2D( vecDelta2D, vecDirection.AsVector2D() ) > 0.8f )
|
||||
{
|
||||
vecDirection = vecDelta;
|
||||
}
|
||||
}
|
||||
|
||||
Vector vecEnd;
|
||||
VectorMA( pOperator->Weapon_ShootPosition(), 32, vecDirection, vecEnd );
|
||||
// Stretch the swing box down to catch low level physics objects
|
||||
CBaseEntity *pHurt = pOperator->CheckTraceHullAttack( pOperator->Weapon_ShootPosition(), vecEnd,
|
||||
Vector(-16,-16,-40), Vector(16,16,16), GetDamageForActivity( GetActivity() ), DMG_CLUB, 0.5f, false );
|
||||
|
||||
// did I hit someone?
|
||||
if ( pHurt )
|
||||
{
|
||||
// play sound
|
||||
WeaponSound( MELEE_HIT );
|
||||
|
||||
CBasePlayer *pPlayer = ToBasePlayer( pHurt );
|
||||
|
||||
bool bFlashed = false;
|
||||
|
||||
// Punch angles
|
||||
if ( pPlayer != NULL && !(pPlayer->GetFlags() & FL_GODMODE) )
|
||||
{
|
||||
float yawKick = random->RandomFloat( -48, -24 );
|
||||
|
||||
//Kick the player angles
|
||||
pPlayer->ViewPunch( QAngle( -16, yawKick, 2 ) );
|
||||
|
||||
Vector dir = pHurt->GetAbsOrigin() - GetAbsOrigin();
|
||||
|
||||
// If the player's on my head, don't knock him up
|
||||
if ( pPlayer->GetGroundEntity() == pOperator )
|
||||
{
|
||||
dir = vecDirection;
|
||||
dir.z = 0;
|
||||
}
|
||||
|
||||
VectorNormalize(dir);
|
||||
|
||||
dir *= 500.0f;
|
||||
|
||||
//If not on ground, then don't make them fly!
|
||||
if ( !(pPlayer->GetFlags() & FL_ONGROUND ) )
|
||||
dir.z = 0.0f;
|
||||
|
||||
//Push the target back
|
||||
pHurt->ApplyAbsVelocityImpulse( dir );
|
||||
|
||||
if ( !bFlashed )
|
||||
{
|
||||
color32 red = {128,0,0,128};
|
||||
UTIL_ScreenFade( pPlayer, red, 0.5f, 0.1f, FFADE_IN );
|
||||
}
|
||||
|
||||
// Force the player to drop anyting they were holding
|
||||
pPlayer->ForceDropOfCarriedPhysObjects();
|
||||
}
|
||||
|
||||
// do effect?
|
||||
}
|
||||
else
|
||||
{
|
||||
WeaponSound( MELEE_MISS );
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets the state of the stun stick
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponStunStick::SetStunState( bool state )
|
||||
{
|
||||
m_bActive = state;
|
||||
|
||||
if ( m_bActive )
|
||||
{
|
||||
//FIXME: START - Move to client-side
|
||||
|
||||
Vector vecAttachment;
|
||||
QAngle vecAttachmentAngles;
|
||||
|
||||
GetAttachment( 1, vecAttachment, vecAttachmentAngles );
|
||||
g_pEffects->Sparks( vecAttachment );
|
||||
|
||||
//FIXME: END - Move to client-side
|
||||
|
||||
EmitSound( "Weapon_StunStick.Activate" );
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitSound( "Weapon_StunStick.Deactivate" );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponStunStick::Deploy( void )
|
||||
{
|
||||
SetStunState( true );
|
||||
|
||||
return BaseClass::Deploy();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponStunStick::Holster( CBaseCombatWeapon *pSwitchingTo )
|
||||
{
|
||||
if ( BaseClass::Holster( pSwitchingTo ) == false )
|
||||
return false;
|
||||
|
||||
SetStunState( false );
|
||||
SetWeaponVisible( false );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &vecVelocity -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponStunStick::Drop( const Vector &vecVelocity )
|
||||
{
|
||||
SetStunState( false );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
UTIL_Remove( this );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWeaponStunStick::GetStunState( void )
|
||||
{
|
||||
return m_bActive;
|
||||
}
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get the attachment point on a viewmodel that a base weapon is using
|
||||
//-----------------------------------------------------------------------------
|
||||
bool UTIL_GetWeaponAttachment( C_BaseCombatWeapon *pWeapon, int attachmentID, Vector &absOrigin, QAngle &absAngles )
|
||||
{
|
||||
// This is already correct in third-person
|
||||
if ( pWeapon && pWeapon->ShouldDrawUsingViewModel() == false )
|
||||
{
|
||||
return pWeapon->GetAttachment( attachmentID, absOrigin, absAngles );
|
||||
}
|
||||
|
||||
// Otherwise we need to translate the attachment to the viewmodel's version and reformat it
|
||||
CBasePlayer *pOwner = ToBasePlayer( pWeapon->GetOwner() );
|
||||
|
||||
if ( pOwner != NULL )
|
||||
{
|
||||
int ret = pOwner->GetViewModel()->GetAttachment( attachmentID, absOrigin, absAngles );
|
||||
FormatViewModelAttachment( absOrigin, true );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Wasn't found
|
||||
return false;
|
||||
}
|
||||
|
||||
#define BEAM_ATTACH_CORE_NAME "sparkrear"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets up the attachment point lookup for the model
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_WeaponStunStick::SetupAttachmentPoints( void )
|
||||
{
|
||||
// Setup points for both types of views
|
||||
if ( ShouldDrawUsingViewModel() )
|
||||
{
|
||||
const char *szBeamAttachNamesTop[NUM_BEAM_ATTACHMENTS] =
|
||||
{
|
||||
"spark1a","spark2a","spark3a","spark4a",
|
||||
"spark5a","spark6a","spark7a","spark8a",
|
||||
"spark9a",
|
||||
};
|
||||
|
||||
const char *szBeamAttachNamesBottom[NUM_BEAM_ATTACHMENTS] =
|
||||
{
|
||||
"spark1b","spark2b","spark3b","spark4b",
|
||||
"spark5b","spark6b","spark7b","spark8b",
|
||||
"spark9b",
|
||||
};
|
||||
|
||||
// Lookup and store all connections
|
||||
for ( int i = 0; i < NUM_BEAM_ATTACHMENTS; i++ )
|
||||
{
|
||||
m_BeamAttachments[i].IDs[0] = LookupAttachment( szBeamAttachNamesTop[i] );
|
||||
m_BeamAttachments[i].IDs[1] = LookupAttachment( szBeamAttachNamesBottom[i] );
|
||||
}
|
||||
|
||||
// Setup the center beam point
|
||||
m_BeamCenterAttachment = LookupAttachment( BEAM_ATTACH_CORE_NAME );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Setup the center beam point
|
||||
m_BeamCenterAttachment = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Draws the stunstick model (with extra effects)
|
||||
//-----------------------------------------------------------------------------
|
||||
int C_WeaponStunStick::DrawModel( int flags )
|
||||
{
|
||||
if ( ShouldDraw() == false )
|
||||
return 0;
|
||||
|
||||
// Only render these on the transparent pass
|
||||
if ( flags & STUDIO_TRANSPARENCY )
|
||||
{
|
||||
DrawEffects();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return BaseClass::DrawModel( flags );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Randomly adds extra effects
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_WeaponStunStick::ClientThink( void )
|
||||
{
|
||||
if ( InSwing() == false )
|
||||
{
|
||||
if ( m_bSwungLastFrame )
|
||||
{
|
||||
// Start fading
|
||||
m_flFadeTime = gpGlobals->curtime;
|
||||
m_bSwungLastFrame = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Remember if we were swinging last frame
|
||||
m_bSwungLastFrame = InSwing();
|
||||
|
||||
if ( IsEffectActive( EF_NODRAW ) )
|
||||
return;
|
||||
|
||||
if ( ShouldDrawUsingViewModel() )
|
||||
{
|
||||
// Update our effects
|
||||
if ( gpGlobals->frametime != 0.0f && ( random->RandomInt( 0, 3 ) == 0 ) )
|
||||
{
|
||||
Vector vecOrigin;
|
||||
QAngle vecAngles;
|
||||
|
||||
// Inner beams
|
||||
BeamInfo_t beamInfo;
|
||||
|
||||
int attachment = random->RandomInt( 0, 15 );
|
||||
|
||||
UTIL_GetWeaponAttachment( this, attachment, vecOrigin, vecAngles );
|
||||
::FormatViewModelAttachment( vecOrigin, false );
|
||||
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
CBaseEntity *pBeamEnt = pOwner->GetViewModel();
|
||||
|
||||
beamInfo.m_vecStart = vec3_origin;
|
||||
beamInfo.m_pStartEnt= pBeamEnt;
|
||||
beamInfo.m_nStartAttachment = attachment;
|
||||
|
||||
beamInfo.m_pEndEnt = NULL;
|
||||
beamInfo.m_nEndAttachment = -1;
|
||||
beamInfo.m_vecEnd = vecOrigin + RandomVector( -8, 8 );
|
||||
|
||||
beamInfo.m_pszModelName = STUNSTICK_BEAM_MATERIAL;
|
||||
beamInfo.m_flHaloScale = 0.0f;
|
||||
beamInfo.m_flLife = 0.05f;
|
||||
beamInfo.m_flWidth = random->RandomFloat( 1.0f, 2.0f );
|
||||
beamInfo.m_flEndWidth = 0;
|
||||
beamInfo.m_flFadeLength = 0.0f;
|
||||
beamInfo.m_flAmplitude = random->RandomFloat( 16, 32 );
|
||||
beamInfo.m_flBrightness = 255.0;
|
||||
beamInfo.m_flSpeed = 0.0;
|
||||
beamInfo.m_nStartFrame = 0.0;
|
||||
beamInfo.m_flFrameRate = 1.0f;
|
||||
beamInfo.m_flRed = 255.0f;;
|
||||
beamInfo.m_flGreen = 255.0f;
|
||||
beamInfo.m_flBlue = 255.0f;
|
||||
beamInfo.m_nSegments = 16;
|
||||
beamInfo.m_bRenderable = true;
|
||||
beamInfo.m_nFlags = 0;
|
||||
|
||||
beams->CreateBeamEntPoint( beamInfo );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Starts the client-side version thinking
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_WeaponStunStick::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
if ( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
||||
SetupAttachmentPoints();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Tells us we're always a translucent entity
|
||||
//-----------------------------------------------------------------------------
|
||||
RenderGroup_t C_WeaponStunStick::GetRenderGroup( void )
|
||||
{
|
||||
return RENDER_GROUP_TWOPASS;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Tells us we're always a translucent entity
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_WeaponStunStick::InSwing( void )
|
||||
{
|
||||
int activity = GetActivity();
|
||||
|
||||
// FIXME: This is needed until the actual animation works
|
||||
if ( ShouldDrawUsingViewModel() == false )
|
||||
return true;
|
||||
|
||||
// These are the swing activities this weapon can play
|
||||
if ( activity == GetPrimaryAttackActivity() ||
|
||||
activity == GetSecondaryAttackActivity() ||
|
||||
activity == ACT_VM_MISSCENTER ||
|
||||
activity == ACT_VM_MISSCENTER2 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Draw our special effects
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_WeaponStunStick::DrawThirdPersonEffects( void )
|
||||
{
|
||||
Vector vecOrigin;
|
||||
QAngle vecAngles;
|
||||
float color[3];
|
||||
float scale;
|
||||
|
||||
CMatRenderContextPtr pRenderContext( materials );
|
||||
IMaterial *pMaterial = materials->FindMaterial( STUNSTICK_GLOW_MATERIAL, NULL, false );
|
||||
pRenderContext->Bind( pMaterial );
|
||||
|
||||
// Get bright when swung
|
||||
if ( InSwing() )
|
||||
{
|
||||
color[0] = color[1] = color[2] = 0.4f;
|
||||
scale = 22.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
color[0] = color[1] = color[2] = 0.1f;
|
||||
scale = 20.0f;
|
||||
}
|
||||
|
||||
// Draw an all encompassing glow around the entire head
|
||||
UTIL_GetWeaponAttachment( this, m_BeamCenterAttachment, vecOrigin, vecAngles );
|
||||
DrawHalo( pMaterial, vecOrigin, scale, color );
|
||||
|
||||
if ( InSwing() )
|
||||
{
|
||||
pMaterial = materials->FindMaterial( STUNSTICK_GLOW_MATERIAL2, NULL, false );
|
||||
pRenderContext->Bind( pMaterial );
|
||||
|
||||
color[0] = color[1] = color[2] = random->RandomFloat( 0.6f, 0.8f );
|
||||
scale = random->RandomFloat( 4.0f, 6.0f );
|
||||
|
||||
// Draw an all encompassing glow around the entire head
|
||||
UTIL_GetWeaponAttachment( this, m_BeamCenterAttachment, vecOrigin, vecAngles );
|
||||
DrawHalo( pMaterial, vecOrigin, scale, color );
|
||||
|
||||
// Update our effects
|
||||
if ( gpGlobals->frametime != 0.0f && ( random->RandomInt( 0, 5 ) == 0 ) )
|
||||
{
|
||||
Vector vecOrigin;
|
||||
QAngle vecAngles;
|
||||
|
||||
GetAttachment( 1, vecOrigin, vecAngles );
|
||||
|
||||
Vector vForward;
|
||||
AngleVectors( vecAngles, &vForward );
|
||||
|
||||
Vector vEnd = vecOrigin - vForward * 1.0f;
|
||||
|
||||
// Inner beams
|
||||
BeamInfo_t beamInfo;
|
||||
|
||||
beamInfo.m_vecStart = vEnd;
|
||||
Vector offset = RandomVector( -12, 8 );
|
||||
|
||||
offset += Vector(4,4,4);
|
||||
beamInfo.m_vecEnd = vecOrigin + offset;
|
||||
|
||||
beamInfo.m_pStartEnt= cl_entitylist->GetEnt( BEAMENT_ENTITY( entindex() ) );
|
||||
beamInfo.m_pEndEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( entindex() ) );
|
||||
beamInfo.m_nStartAttachment = 1;
|
||||
beamInfo.m_nEndAttachment = -1;
|
||||
|
||||
beamInfo.m_nType = TE_BEAMTESLA;
|
||||
beamInfo.m_pszModelName = STUNSTICK_BEAM_MATERIAL;
|
||||
beamInfo.m_flHaloScale = 0.0f;
|
||||
beamInfo.m_flLife = 0.01f;
|
||||
beamInfo.m_flWidth = random->RandomFloat( 1.0f, 3.0f );
|
||||
beamInfo.m_flEndWidth = 0;
|
||||
beamInfo.m_flFadeLength = 0.0f;
|
||||
beamInfo.m_flAmplitude = random->RandomFloat( 1, 2 );
|
||||
beamInfo.m_flBrightness = 255.0;
|
||||
beamInfo.m_flSpeed = 0.0;
|
||||
beamInfo.m_nStartFrame = 0.0;
|
||||
beamInfo.m_flFrameRate = 1.0f;
|
||||
beamInfo.m_flRed = 255.0f;;
|
||||
beamInfo.m_flGreen = 255.0f;
|
||||
beamInfo.m_flBlue = 255.0f;
|
||||
beamInfo.m_nSegments = 16;
|
||||
beamInfo.m_bRenderable = true;
|
||||
beamInfo.m_nFlags = FBEAM_SHADEOUT;
|
||||
|
||||
beams->CreateBeamPoints( beamInfo );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Draw our special effects
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_WeaponStunStick::DrawFirstPersonEffects( void )
|
||||
{
|
||||
Vector vecOrigin;
|
||||
QAngle vecAngles;
|
||||
float color[3];
|
||||
float scale;
|
||||
|
||||
CMatRenderContextPtr pRenderContext( materials );
|
||||
IMaterial *pMaterial = materials->FindMaterial( STUNSTICK_GLOW_MATERIAL_NOZ, NULL, false );
|
||||
// FIXME: Needs to work with new IMaterial system!
|
||||
pRenderContext->Bind( pMaterial );
|
||||
|
||||
// Find where we are in the fade
|
||||
float fadeAmount = RemapValClamped( gpGlobals->curtime, m_flFadeTime, m_flFadeTime + FADE_DURATION, 1.0f, 0.1f );
|
||||
|
||||
// Get bright when swung
|
||||
if ( InSwing() )
|
||||
{
|
||||
color[0] = color[1] = color[2] = 0.4f;
|
||||
scale = 22.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
color[0] = color[1] = color[2] = 0.4f * fadeAmount;
|
||||
scale = 20.0f;
|
||||
}
|
||||
|
||||
if ( color[0] > 0.0f )
|
||||
{
|
||||
// Draw an all encompassing glow around the entire head
|
||||
UTIL_GetWeaponAttachment( this, m_BeamCenterAttachment, vecOrigin, vecAngles );
|
||||
DrawHalo( pMaterial, vecOrigin, scale, color );
|
||||
}
|
||||
|
||||
// Draw bright points at each attachment location
|
||||
for ( int i = 0; i < (NUM_BEAM_ATTACHMENTS*2)+1; i++ )
|
||||
{
|
||||
if ( InSwing() )
|
||||
{
|
||||
color[0] = color[1] = color[2] = random->RandomFloat( 0.05f, 0.5f );
|
||||
scale = random->RandomFloat( 4.0f, 5.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
color[0] = color[1] = color[2] = random->RandomFloat( 0.05f, 0.5f ) * fadeAmount;
|
||||
scale = random->RandomFloat( 4.0f, 5.0f ) * fadeAmount;
|
||||
}
|
||||
|
||||
if ( color[0] > 0.0f )
|
||||
{
|
||||
UTIL_GetWeaponAttachment( this, i, vecOrigin, vecAngles );
|
||||
DrawHalo( pMaterial, vecOrigin, scale, color );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Draw our special effects
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_WeaponStunStick::DrawEffects( void )
|
||||
{
|
||||
if ( ShouldDrawUsingViewModel() )
|
||||
{
|
||||
DrawFirstPersonEffects();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawThirdPersonEffects();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Viewmodel was drawn
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_WeaponStunStick::ViewModelDrawn( C_BaseViewModel *pBaseViewModel )
|
||||
{
|
||||
// Don't bother when we're not deployed
|
||||
if ( IsWeaponVisible() )
|
||||
{
|
||||
// Do all our special effects
|
||||
DrawEffects();
|
||||
}
|
||||
|
||||
BaseClass::ViewModelDrawn( pBaseViewModel );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Draw a cheap glow quad at our impact point (with sparks)
|
||||
//-----------------------------------------------------------------------------
|
||||
void StunstickImpactCallback( const CEffectData &data )
|
||||
{
|
||||
float scale = random->RandomFloat( 16, 32 );
|
||||
|
||||
FX_AddQuad( data.m_vOrigin,
|
||||
data.m_vNormal,
|
||||
scale,
|
||||
scale*2.0f,
|
||||
1.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
random->RandomInt( 0, 360 ),
|
||||
0,
|
||||
Vector( 1.0f, 1.0f, 1.0f ),
|
||||
0.1f,
|
||||
"sprites/light_glow02_add",
|
||||
0 );
|
||||
|
||||
FX_Sparks( data.m_vOrigin, 1, 2, data.m_vNormal, 6, 64, 256 );
|
||||
}
|
||||
|
||||
DECLARE_CLIENT_EFFECT( "StunstickImpact", StunstickImpactCallback );
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user