This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+172
View File
@@ -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
+577
View File
@@ -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
}
+97
View File
@@ -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
+32
View File
@@ -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 );
}
+35
View File
@@ -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
+154
View File
@@ -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 );
}
}
+312
View File
@@ -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;
}
+84
View File
@@ -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
+956
View File
@@ -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 );
}
+228
View File
@@ -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;
}
+70
View File
@@ -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
+552
View File
@@ -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;
}
+330
View File
@@ -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
+93
View File
@@ -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
+30
View File
@@ -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
+339
View File
@@ -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
+267
View File
@@ -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
+634
View File
@@ -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
+91
View File
@@ -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
+264
View File
@@ -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;
}
+902
View File
@@ -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